diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..def5ba5d90b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + + - package-ecosystem: "gradle" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/compute-entropy.py b/.github/workflows/compute-entropy.py new file mode 100644 index 00000000000..5225542b1ff --- /dev/null +++ b/.github/workflows/compute-entropy.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +import os +import sys +import math +import json +import subprocess +from collections import Counter +from pathlib import Path + +def shannon_entropy(text: str) -> float: + if not text or len(text) < 10: + return 0.0 + freq = Counter(text) + probs = [count / len(text) for count in freq.values()] + return -sum(p * math.log2(p) for p in probs if p > 0) + +# Determine changed files based on event type +changed_files = [] +event_name = os.environ.get("EVENT_NAME", "") +base_sha = os.environ.get("BASE_SHA", "").strip() +head_sha = os.environ.get("HEAD_SHA", "").strip() or "HEAD" + +try: + if event_name == "pull_request_target" and base_sha: + # PR case: we checked out the PR head and fetched the base commit + changed_files = subprocess.check_output( + ["git", "diff", "--name-only", base_sha, head_sha], + text=True + ).splitlines() + else: + # push / release: diff against previous commit + changed_files = subprocess.check_output( + ["git", "diff", "--name-only", "HEAD~1", "HEAD"], + text=True + ).splitlines() +except subprocess.CalledProcessError: + # Fallbacks + try: + changed_files = subprocess.check_output( + ["git", "diff", "--name-only", "HEAD~1", "HEAD"], + text=True + ).splitlines() + except subprocess.CalledProcessError: + changed_files = subprocess.check_output( + ["git", "ls-files"], text=True + ).splitlines() + +results = [] +total_ent = 0.0 +count = 0 + +for f in changed_files: + path = Path(f.strip()) + if not path.exists() or path.suffix in {'.png', '.jpg', '.gif', '.bin', '.lock', '.exe', '.dll', '.so'}: + continue + try: + content = path.read_text(encoding="utf-8", errors="ignore") + ent = shannon_entropy(content) + results.append(f"{f}: {ent:.3f}") + total_ent += ent + count += 1 + except Exception: + pass + +avg = round(total_ent / count, 3) if count > 0 else 0.0 + +verdict = ( + "✅ Mid-4 beauty detected (thoughtful human code!)" if 4.3 <= avg <= 4.7 else + "⚠️ Consider review — entropy outside sweet spot" if avg > 0 else + "No source files changed" +) + +with open("/tmp/beauty.json", "w") as f: + json.dump({ + "average_entropy": avg, + "verdict": verdict, + "files": results[:20] + }, f, indent=2) + +print(f"Average entropy: {avg}") +print(verdict) \ No newline at end of file diff --git a/.github/workflows/entropy-beauty-scan.yml b/.github/workflows/entropy-beauty-scan.yml new file mode 100644 index 00000000000..3b2c0c18727 --- /dev/null +++ b/.github/workflows/entropy-beauty-scan.yml @@ -0,0 +1,151 @@ +name: Entropy Beauty + TruffleHog Scan + +on: [push, release, pull_request_target] + +permissions: + contents: read + pull-requests: write + issues: write # must be at workflow level for push/merge events + +jobs: + scan: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }} + fetch-depth: ${{ github.event_name == 'pull_request_target' && 1 || 2 }} + allow-unsafe-pr-checkout: ${{ github.event_name == 'pull_request_target' }} + + - name: Fetch PR base commit (needed for accurate diff) + if: github.event_name == 'pull_request_target' + run: git fetch origin ${{ github.event.pull_request.base.sha }} --depth=1 + + - name: Cache pip manually + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-entropy-${{ hashFiles('.github/workflows/compute-entropy.py') }} + restore-keys: | + ${{ runner.os }}-pip-entropy- + + - name: Setup Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: '3.12' + + - name: Install Python dependencies (only when needed) + run: | + python -m pip install --upgrade pip + # No extra packages needed — compute-entropy.py uses only stdlib + + - name: Run TruffleHog + uses: trufflesecurity/trufflehog@27b0417c16317ca9a472a9a8092acce143b49c55 # v3.95.9 + with: + path: . + extra_args: --results=verified,unknown --filter-entropy=3.5 --json + + - name: Compute mid-4 beauty entropy + env: + EVENT_NAME: ${{ github.event_name }} + BASE_SHA: ${{ github.event.pull_request.base.sha || '' }} + HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + run: python .github/workflows/compute-entropy.py + + - name: Post summary comment (PR only) + if: github.event_name == 'pull_request' || github.event_name == 'pull_request_target' + uses: actions/github-script@v9 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + + // Read TruffleHog output — it prints one JSON object per line (NDJSON) + let findings = []; + if (fs.existsSync('trufflehog.json')) { + try { + const lines = fs.readFileSync('trufflehog.json', 'utf8').trim().split('\n'); + findings = lines.map(line => { + try { return JSON.parse(line); } catch(e) { return null; } + }).filter(Boolean); + } catch(e) {} + } else { + console.log("No trufflehog.json found, using empty findings"); + } + + const beauty = JSON.parse(fs.readFileSync('/tmp/beauty.json', 'utf8')); + + let body = `## 🐷 TruffleHog + Entropy Beauty Scan\n\n`; + body += `**Average entropy of changed code:** ${beauty.average_entropy} bits/char\n`; + body += `**Verdict:** ${beauty.verdict}\n\n`; + + if (beauty.files && beauty.files.length) { + body += `**Changed files entropy:**\n\`\`\`\n${beauty.files.join('\n')}\n\`\`\`\n\n`; + } + + if (findings.length > 0) { + body += `⚠️ **TruffleHog found ${findings.length} potential issue(s)**\n`; + } else { + body += `✅ No secrets or suspicious high-entropy strings found.\n`; + } + + body += `\n*Mid-4 beauty heuristic in action — powered by our entropy chats! 😊*`; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: body + }); + + # ── Create issue on push ONLY if suspicious (entropy outside 4.3–5.1) ── + - name: Create issue on suspicious push + if: github.event_name == 'push' || github.event_name == 'release' + uses: actions/github-script@v9 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const beauty = JSON.parse(fs.readFileSync('/tmp/beauty.json', 'utf8')); + + // Only create issue if it's NOT beautiful mid-4 + if (beauty.average_entropy >= 4.3 && beauty.average_entropy <= 5.1) { + console.log("✅ Mid-4 beauty — no issue created"); + return; + } + + let findings = []; + if (fs.existsSync('trufflehog.json')) { + try { + const lines = fs.readFileSync('trufflehog.json', 'utf8').trim().split('\n'); + findings = lines.map(line => { + try { return JSON.parse(line); } catch(e) { return null; } + }).filter(Boolean); + } catch(e) {} + } + + let body = `**Average entropy:** ${beauty.average_entropy} bits/char\n\n`; + body += `**Verdict:** ${beauty.verdict}\n\n`; + + if (beauty.files && beauty.files.length) { + body += `**Changed files:**\n\`\`\`\n${beauty.files.join('\n')}\n\`\`\`\n\n`; + } + + if (findings.length > 0) { + body += `**TruffleHog found ${findings.length} potential issue(s)**\n`; + } else { + body += `✅ No secrets or suspicious high-entropy strings found.\n`; + } + + body += `\n*Triggered by push to \`${context.sha}\` — mid-4 beauty heuristic*`; + + await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: `🚨 Suspicious entropy detected in recent push (${beauty.average_entropy})`, + body: body, + labels: ['entropy', 'security', 'review-needed'] + }); + + console.log("⚠️ Created issue because entropy was outside mid-4 range"); diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml new file mode 100644 index 00000000000..4174da20727 --- /dev/null +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -0,0 +1,13 @@ +name: "Validate Gradle Wrapper" +on: [push, pull_request] + +permissions: + contents: read + +jobs: + validation: + name: "Validation" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: gradle/wrapper-validation-action@f9c9c575b8b21b6485636a91ffecd10e558c62f6 # v3.5.0 diff --git a/.github/workflows/gradle_branch.yml b/.github/workflows/gradle_branch.yml new file mode 100644 index 00000000000..ef7ad91cc20 --- /dev/null +++ b/.github/workflows/gradle_branch.yml @@ -0,0 +1,37 @@ +# This workflow will build a Java project with Gradle +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: Branch + +on: + push: + branches-ignore: [ '3.x' ] + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Set up JDK 11 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + with: + distribution: 'zulu' + java-version: '11' + - name: Cache Gradle packages + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ secrets.CACHE_VERSION }}-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle-${{ secrets.CACHE_VERSION }} + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build RxJava + run: ./gradlew build --stacktrace + - name: Upload to Codecov + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 + - name: Generate Javadoc + run: ./gradlew javadoc --stacktrace diff --git a/.github/workflows/gradle_jdk11.yml b/.github/workflows/gradle_jdk11.yml new file mode 100644 index 00000000000..8eab1cf14a3 --- /dev/null +++ b/.github/workflows/gradle_jdk11.yml @@ -0,0 +1,42 @@ +# This workflow will build a Java project with Gradle +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: JDK 11 + +on: + push: + branches: [ 3.x ] + pull_request: + branches: [ 3.x ] + +permissions: + contents: read + +env: + BUILD_WITH_11: true + +jobs: + build: + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Set up JDK 11 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + with: + distribution: 'zulu' + java-version: '11' + - name: Cache Gradle packages + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-1-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle-1- + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Verify generated module-info + run: ./gradlew -PjavaCompatibility=9 jar + - name: Build RxJava + run: ./gradlew build --stacktrace +# - name: Generate Javadoc +# run: ./gradlew javadoc --stacktrace diff --git a/.github/workflows/gradle_pr.yml b/.github/workflows/gradle_pr.yml new file mode 100644 index 00000000000..815b14d9631 --- /dev/null +++ b/.github/workflows/gradle_pr.yml @@ -0,0 +1,37 @@ +# This workflow will build a Java project with Gradle +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: Pull Request + +on: + pull_request: + branches: [ 3.x ] + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Set up JDK 11 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + with: + distribution: 'zulu' + java-version: '11' + - name: Cache Gradle packages + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-1-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle-1- + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build RxJava + run: ./gradlew build --stacktrace + - name: Upload to Codecov + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 + - name: Generate Javadoc + run: ./gradlew javadoc --stacktrace diff --git a/.github/workflows/gradle_release.yml b/.github/workflows/gradle_release.yml new file mode 100644 index 00000000000..3d3ddc27f25 --- /dev/null +++ b/.github/workflows/gradle_release.yml @@ -0,0 +1,70 @@ +# This workflow will build a Java project with Gradle +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: Release + +on: + release: + types: [ released, prereleased ] + branches: [ '3.x' ] + tags: + - 'v3.*.*' + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: write + env: + CI_BUILD_NUMBER: ${{ github.run_number }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Set up JDK 11 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + with: + distribution: 'zulu' + java-version: '11' + - name: Cache Gradle packages + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ secrets.CACHE_VERSION }}-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle-${{ secrets.CACHE_VERSION }} + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Grant execute permission for push + run: chmod +x push_javadoc.sh + - name: Extract version tag + run: echo "BUILD_TAG=${GITHUB_REF:10}" >> $GITHUB_ENV + - name: Build RxJava + run: ./gradlew build --stacktrace --no-daemon + - name: Upload to Codecov + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 +# - name: Upload release +# run: ./gradlew -PreleaseMode=full publish --no-daemon --no-parallel --stacktrace +# env: +# # Define secrets at https://github.com/ReactiveX/RxJava/settings/secrets/actions +# # ------------------------------------------------------------------------------ +# ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_USER }} +# ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_PASSWORD }} +# ORG_GRADLE_PROJECT_SIGNING_PRIVATE_KEY: ${{ secrets.SIGNING_PRIVATE_KEY }} +# ORG_GRADLE_PROJECT_SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} + - name: Publish release + run: ./gradlew -PreleaseMode=full publishAndReleaseToMavenCentral --no-configuration-cache --no-daemon --no-parallel --stacktrace + env: + # Define secrets at https://github.com/ReactiveX/RxJava/settings/secrets/actions + # ------------------------------------------------------------------------------ + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_USER }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_PASSWORD }} + ORG_GRADLE_PROJECT_SIGNING_PRIVATE_KEY: ${{ secrets.SIGNING_PRIVATE_KEY }} + ORG_GRADLE_PROJECT_SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} + - name: Push Javadoc + run: ./push_javadoc.sh + env: + # Define secrets at https://github.com/ReactiveX/RxJava/settings/secrets/actions + # ------------------------------------------------------------------------------ + JAVADOCS_TOKEN: ${{ secrets.JAVADOCS_TOKEN }} diff --git a/.github/workflows/gradle_snapshot.yml b/.github/workflows/gradle_snapshot.yml new file mode 100644 index 00000000000..e56c9019aad --- /dev/null +++ b/.github/workflows/gradle_snapshot.yml @@ -0,0 +1,56 @@ +# This workflow will build a Java project with Gradle +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: Snapshot + +on: + push: + branches: [ '3.x' ] + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + if: github.repository == 'ReactiveX/RxJava' + permissions: + contents: write + env: + # ------------------------------------------------------------------------------ + CI_BUILD_NUMBER: ${{ github.run_number }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Set up JDK 11 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + with: + distribution: 'zulu' + java-version: '11' + - name: Cache Gradle packages + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ secrets.CACHE_VERSION }}-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle-${{ secrets.CACHE_VERSION }} + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Grant execute permission for push + run: chmod +x push_javadoc.sh + - name: Build RxJava + run: ./gradlew build --stacktrace --no-daemon + - name: Upload Snapshot + run: ./gradlew -PreleaseMode=branch publishAllPublicationsToMavenCentralRepository --no-daemon --no-parallel --stacktrace + env: + # Define secrets at https://github.com/ReactiveX/RxJava/settings/secrets/actions + # ------------------------------------------------------------------------------ + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_USER }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_PASSWORD }} + - name: Upload to Codecov + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 + - name: Push Javadoc + run: ./push_javadoc.sh + # Define secrets at https://github.com/ReactiveX/RxJava/settings/secrets/actions + # ------------------------------------------------------------------------------ + env: + JAVADOCS_TOKEN: ${{ secrets.JAVADOCS_TOKEN }} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 00000000000..26a487cffea --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,59 @@ +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '43 12 * * 4' + push: + branches: [ "3.x" ] + +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + + steps: + - name: "Checkout code" + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if + # you want to enable the Branch-Protection check on a *public* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-fine-grained-pat-optional. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 + with: + sarif_file: results.sarif diff --git a/.gitignore b/.gitignore index 428d55b2fb3..b60171cf2df 100644 --- a/.gitignore +++ b/.gitignore @@ -73,4 +73,10 @@ bin/ # PMD files .pmd .ruleset -test-output/ \ No newline at end of file +test-output/ + +# Checkstyle local config +.checkstyle + +# Some editor's config +.editorconfig diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 00000000000..954870bba66 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,139 @@ +## Learn more about this file at 'https://www.gitpod.io/docs/references/gitpod-yml' +## +## This '.gitpod.yml' file when placed at the root of a project instructs +## Gitpod how to prepare & build the project, start development environments +## and configure continuous prebuilds. Prebuilds when enabled builds a project +## like a CI server so you can start coding right away - no more waiting for +## dependencies to download and builds to finish when reviewing pull-requests +## or hacking on something new. +## +## With Gitpod you can develop software from any device (even iPads) via +## desktop or browser based versions of VS Code or any JetBrains IDE and +## customise it to your individual needs - from themes to extensions, you +## have full control. +## +## The easiest way to try out Gitpod is install the browser extenion: +## 'https://www.gitpod.io/docs/browser-extension' or by prefixing +## 'https://gitpod.io#' to the source control URL of any project. +## +## For example: 'https://gitpod.io#https://github.com/gitpod-io/gitpod' + + +## The 'image' section defines which Docker image Gitpod should use. +## By default, Gitpod uses a standard Docker Image called 'workspace-full' +## which can be found at 'https://github.com/gitpod-io/workspace-images' +## +## Workspaces started based on this default image come pre-installed with +## Docker, Go, Java, Node.js, C/C++, Python, Ruby, Rust, PHP as well as +## tools such as Homebrew, Tailscale, Nginx and several more. +## +## If this image does not include the tools needed for your project then +## a public Docker image or your own Docker file can be configured. +## +## Learn more about images at 'https://www.gitpod.io/docs/config-docker' + +#image: node:buster # use 'https://hub.docker.com/_/node' +# +#image: # leave image undefined if using a Dockerfile +# file: .gitpod.Dockerfile # relative path to the Dockerfile from the +# # root of the project + +## The 'tasks' section defines how Gitpod prepares and builds this project +## or how Gitpod can start development servers. With Gitpod, there are three +## types of tasks: +## +## - before: Use this for tasks that need to run before init and before command. +## - init: Use this to configure prebuilds of heavy-lifting tasks such as +## downloading dependencies or compiling source code. +## - command: Use this to start your database or application when the workspace starts. +## +## Learn more about these tasks at 'https://www.gitpod.io/docs/config-start-tasks' + +#tasks: +# - before: | +# # commands to execute... +# +# - init: | +# # sudo apt-get install python3 # can be used to install operating system +# # dependencies but these are not kept after the +# # prebuild completes thus Gitpod recommends moving +# # operating system dependency installation steps +# # to a custom Dockerfile to make prebuilds faster +# # and to keep your codebase DRY. +# # 'https://www.gitpod.io/docs/config-docker' +# +# # pip install -r requirements.txt # install codebase dependencies +# # cmake # precompile codebase +# +# - name: Web Server +# openMode: split-left +# env: +# WEBSERVER_PORT: 8080 +# command: | +# python3 -m http.server $WEBSERVER_PORT +# +# - name: Web Browser +# openMode: split-right +# env: +# WEBSERVER_PORT: 8080 +# command: | +# gp await-port $WEBSERVER_PORT +# lynx `gp url` + +tasks: + - command: ./gradlew build + +## The 'ports' section defines various ports your may listen on are +## configured in Gitpod on an authenticated URL. By default, all ports +## are in private visibility state. +## +## Learn more about ports at 'https://www.gitpod.io/docs/config-ports' + +#ports: +# - port: 8080 # alternatively configure entire ranges via '8080-8090' +# visibility: private # either 'public' or 'private' (default) +# onOpen: open-browser # either 'open-browser', 'open-preview' or 'ignore' + + +## The 'vscode' section defines a list of Visual Studio Code extensions from +## the OpenVSX.org registry to be installed upon workspace startup. OpenVSX +## is an open alternative to the proprietary Visual Studio Code Marketplace +## and extensions can be added by sending a pull-request with the extension +## identifier to https://github.com/open-vsx/publish-extensions +## +## The identifier of an extension is always ${publisher}.${name}. +## +## For example: 'vscodevim.vim' +## +## Learn more at 'https://www.gitpod.io/docs/ides-and-editors/vscode' + +#vscode: +# extensions: +# - vscodevim.vim +# - esbenp.prettier-vscode@9.5.0 +# - https://example.com/abc/releases/extension-0.26.0.vsix + + +## The 'github' section defines configuration of continuous prebuilds +## for GitHub repositories when the GitHub application +## 'https://github.com/apps/gitpod-io' is installed in GitHub and granted +## permissions to access the repository. +## +## Learn more at 'https://www.gitpod.io/docs/prebuilds' + +github: + prebuilds: + # enable for the default branch + master: true + # enable for all branches in this repo + branches: true + # enable for pull requests coming from this repo + pullRequests: true + # enable for pull requests coming from forks + pullRequestsFromForks: true + # add a check to pull requests + addCheck: true + # add a "Review in Gitpod" button as a comment to pull requests + addComment: false + # add a "Review in Gitpod" button to the pull request's description + addBadge: true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6e595b4e930..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -language: java -jdk: -- openjdk8 - -# prevent travis running gradle assemble; let the build script do it anyway -install: true - -# running in container causes test failures and 2x-3x longer build, use standalone instances -sudo: required - -# script for build and release via Travis to Bintray -script: gradle/buildViaTravis.sh - -# Code coverage -after_success: - - bash <(curl -s --retry 10 https://codecov.io/bash) - - bash gradle/push_javadoc.sh - -# cache between builds -cache: - directories: - - $HOME/.m2 - - $HOME/.gradle -env: - global: - - secure: YcLpYfNc/dyDON+oDvnJK5pFNhpPeJHxlAHV8JBt42e51prAl6njqrg1Qlfdp0pvBiskTPQHUxbFy9DOB1Z+43lPj5vlqz6qBgtS3vtBnsrczr+5Xx7NTdVKq6oZGl45VjfNPT7zdM6GQ5ifdzOid6kJIFu34g9JZkCzOY3BWGM= - - secure: WVmfSeW1UMNdem7+X4cVDjkEkqdeNavYH4udn3bFN1IFaWdliWFp4FYVBVi+p1T/IgkRSqzoW9Bm43DABe1UMFoErFCbfd7B0Ofgb4NZAsxFgokHGVLCe6k5+rQyASseiO7k0itSj3Kq9TrDueKPhv+g+IG0w1A8yZTnXdhXHvY= - - secure: Xt8E09nmSr+5r7ly95hG/EiBitZbhFGPRGp8oqPkNn1A2fzG9+hnvlNLgQhVPsISZGzJwkWa3LGBxAVGmuysVOz7eCwkoqlDZaaSLYAPfWXqkr+cmYGPkErgHSp+n/hnQG4TylX0YxzqX8flr6db21zWyNduiyHmo+xFydI5LeM= - - secure: RmpIsmYa5BdLLWR6DILjhEE/dx2q3O0NIkvnMx5G1cyRCNCrOf1B7fYFHnsTDwpvRA+6H6dZinmeyf6D3G+czOG5q/TW2jcu5nh+YOLhBb6jPIqRDfq/WHAa5Lkdssxs5g9RdWlEDVFMoE62lGc4cnfJz5F5puH29dy2SvXxIQw= diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4547f563a86..88fa4481333 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,31 @@ # Contributing to RxJava 3.x +:warning: We ask you to contribute your change to the 4.x branch because since March 2026, we are developing RxJava 4.0.0 only. It will be then decided if a backport is necessary or feasible. We do not plan to release any more 3.x versions unless there is a very good reason or a flaw that needs patching and cannot be worked around otherwise. + +Thank you for your consideration. + +------------ + If you would like to contribute code you can do so through GitHub by forking the repository and sending a pull request targeting the branch `3.x`. When submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible. +## AI contributions + +We are not against contributions from AI tools, LLM-based or future architectures. However, you as a human are responsible for its contributions and suggestions. + +This means, you have to make sure it doesn't hallucinate issues or elements of the contribution, doesn't try to hack rewards or hack established unit tests, doesn't go wild +and rearchitect established components. + +If you post a contribution that is broken, we will not argue with your LLM or prompt engineer for you. You are responsible for having the the LLM's output work within the confines +of this project. + +Please also be aware that this project is large both in current and historical sense with some rules not documented or enforced by unit tests. This is because such unwritten rules +were trivial or readily inferrable by humans in the past. The project predates LLMs several years and thus is not organized to be accessible by LLMs today. Nor should it be. + +Consequently, the amount of prompting and the context window size to include all possible information about it could become so much that it can become prohibitively expensive to have +an LLM come up with more than basic and trivial contributions. Needless to say, don't bankrupt yourself and don't just accept the LLM's output at face value. + ## License By contributing your code, you agree to license your contribution under the terms of the APLv2: https://github.com/ReactiveX/RxJava/blob/3.x/LICENSE @@ -13,19 +35,16 @@ All files are released with the Apache 2.0 license. If you are adding a new file it should have a header like this: ``` -/** +/* * Copyright (c) 2016-present, RxJava Contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ ``` diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 00000000000..5d2c6e53f3c --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,13 @@ +Copyright (c) 2016-present, RxJava Contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md index 698aa96f40d..5276c0bd375 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ # RxJava: Reactive Extensions for the JVM - + [![codecov.io](http://codecov.io/github/ReactiveX/RxJava/coverage.svg?branch=3.x)](https://codecov.io/gh/ReactiveX/RxJava/branch/3.x) -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.reactivex.rxjava3/rxjava/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.reactivex.rxjava3/rxjava) +[![Maven Central](https://maven-badges.sml.io/sonatype-central/io.reactivex.rxjava3/rxjava/badge.svg)](https://maven-badges.sml.io/sonatype-central/io.reactivex.rxjava3/rxjava) +[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod)](https://gitpod.io/#https://github.com/ReactiveX/RxJava) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/ReactiveX/RxJava/badge)](https://securityscorecards.dev/viewer/?uri=github.com/ReactiveX/RxJava) RxJava is a Java VM implementation of [Reactive Extensions](http://reactivex.io): a library for composing asynchronous and event-based programs by using observable sequences. @@ -10,22 +12,27 @@ It extends the [observer pattern](http://en.wikipedia.org/wiki/Observer_pattern) #### Version 3.x ([Javadoc](http://reactivex.io/RxJava/3.x/javadoc/)) -- single dependency: [Reactive-Streams](https://github.com/reactive-streams/reactive-streams-jvm) -- Java 8+ ([Android](https://github.com/ReactiveX/RxAndroid) desugar friendly) -- Java 8 lambda-friendly API -- fixed API mistakes and many limits of RxJava 2 -- intended to be a replacement for RxJava 2 with relatively few binary incompatible changes -- non-opinionated about the source of concurrency (threads, pools, event loops, fibers, actors, etc.) -- async or synchronous execution -- virtual time and schedulers for parameterized concurrency -- test and diagnostic support via test schedulers, test consumers and plugin hooks +- Single dependency: [Reactive-Streams](https://github.com/reactive-streams/reactive-streams-jvm). +- Java 8+ or Android API 21+ required. +- Java 8 lambda-friendly API. +- [Android](https://github.com/ReactiveX/RxAndroid) desugar friendly. +- Fixed API mistakes and many limits of RxJava 2. +- Intended to be a replacement for RxJava 2 with relatively few binary incompatible changes. +- Non-opinionated about the source of concurrency (threads, pools, event loops, fibers, actors, etc.). +- Async or synchronous execution. +- Virtual time and schedulers for parameterized concurrency. +- Test and diagnostic support via test schedulers, test consumers and plugin hooks. +- Interop with newer JDK versions via 3rd party libraries, such as + - [Java 9 Flow API](https://github.com/akarnokd/RxJavaJdk9Interop#rxjavajdk9interop) + - [Java 21 Virtual Threads](https://github.com/akarnokd/RxJavaFiberInterop#rxjavafiberinterop) Learn more about RxJava in general on the Wiki Home. +:information_source: Please read the [What's different in 3.0](https://github.com/ReactiveX/RxJava/wiki/What's-different-in-3.0) for details on the changes and migration information when upgrading from 2.x. + #### Version 2.x -The [2.x version](https://github.com/ReactiveX/RxJava/tree/2.x) will be supported with bugfixes and important documentation updates until -**December 31, 2020**. No new features will be added to 2.x. +The [2.x version](https://github.com/ReactiveX/RxJava/tree/2.x) is end-of-life as of **February 28, 2021**. No further development, support, maintenance, PRs and updates will happen. The [Javadoc]([Javadoc](http://reactivex.io/RxJava/2.x/javadoc/)) of the very last version, **2.2.21**, will remain accessible. #### Version 1.x @@ -41,7 +48,7 @@ The first step is to include RxJava 3 into your project, for example, as a Gradl implementation "io.reactivex.rxjava3:rxjava:3.x.y" ``` -(Please replace `x` and `y` with the latest version numbers: [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.reactivex.rxjava3/rxjava/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.reactivex.rxjava3/rxjava) +(Please replace `x` and `y` with the latest version numbers: [![Maven Central](https://maven-badges.sml.io/sonatype-central/io.reactivex.rxjava3/rxjava/badge.svg)](https://maven-badges.sml.io/sonatype-central/io.reactivex.rxjava3/rxjava) ) ### Hello World @@ -194,7 +201,7 @@ RxJava operators don't work with `Thread`s or `ExecutorService`s directly but wi - `Schedulers.single()`: Run work on a single thread in a sequential and FIFO manner. - `Schedulers.trampoline()`: Run work in a sequential and FIFO manner in one of the participating threads, usually for testing purposes. -These are available on all JVM platforms but some specific platforms, such as Android, have their own typical `Scheduler`s defined: `AndroidSchedulers.mainThread()`, `SwingScheduler.instance()` or `JavaFXSchedulers.gui()`. +These are available on all JVM platforms but some specific platforms, such as Android, have their own typical `Scheduler`s defined: `AndroidSchedulers.mainThread()`, `SwingScheduler.instance()` or `JavaFXScheduler.platform()`. In addition, there is an option to wrap an existing `Executor` (and its subtypes such as `ExecutorService`) into a `Scheduler` via `Schedulers.from(Executor)`. This can be used, for example, to have a larger but still fixed pool of threads (unlike `computation()` and `io()` respectively). @@ -503,7 +510,7 @@ For further details, consult the [wiki](https://github.com/ReactiveX/RxJava/wiki - Google Group: [RxJava](http://groups.google.com/d/forum/rxjava) - Twitter: [@RxJava](http://twitter.com/RxJava) - [GitHub Issues](https://github.com/ReactiveX/RxJava/issues) -- StackOverflow: [rx-java](http://stackoverflow.com/questions/tagged/rx-java) and [rx-java2](http://stackoverflow.com/questions/tagged/rx-java2) +- StackOverflow: [rx-java](http://stackoverflow.com/questions/tagged/rx-java), [rx-java2](http://stackoverflow.com/questions/tagged/rx-java2) and [rx-java3](http://stackoverflow.com/questions/tagged/rx-java3) - [Gitter.im](https://gitter.im/ReactiveX/RxJava) ## Versioning @@ -524,7 +531,7 @@ APIs marked with the [`@Experimental`][experimental source link] annotation at t #### @Deprecated -APIs marked with the `@Deprecated` annotation at the class or method level will remain supported until the next major release but it is recommended to stop using them. +APIs marked with the `@Deprecated` annotation at the class or method level will remain supported until the next major release, but it is recommended to stop using them. #### io.reactivex.rxjava3.internal.* @@ -564,19 +571,19 @@ and for Ivy: ### Snapshots -Snapshots are available via https://oss.jfrog.org/libs-snapshot/io/reactivex/rxjava3/rxjava/ +Snapshots after May 19st, 2025 are available via https://central.sonatype.com/repository/maven-snapshots/io/reactivex/rxjava3/rxjava/ ```groovy repositories { - maven { url 'https://oss.jfrog.org/libs-snapshot' } + maven { url 'https://central.sonatype.com/repository/maven-snapshots' } } dependencies { - compile 'io.reactivex.rxjava3:rxjava:3.0.0-SNAPSHOT' + implementation 'io.reactivex.rxjava3:rxjava:3.0.0-SNAPSHOT' } ``` -JavaDoc snapshots are available at http://reactivex.io/RxJava/3.x/javadoc/snapshot +JavaDoc snapshots are available at https://reactivex.io/RxJava/3.x/javadoc/snapshot ## Build @@ -611,5 +618,5 @@ For bugs, questions and discussions please use the [Github Issues](https://githu See the License for the specific language governing permissions and limitations under the License. -[beta source link]: https://github.com/ReactiveX/RxJava/blob/3.x/src/main/java/io/reactivex/annotations/Beta.java -[experimental source link]: https://github.com/ReactiveX/RxJava/blob/3.x/src/main/java/io/reactivex/annotations/Experimental.java +[beta source link]: https://github.com/ReactiveX/RxJava/blob/3.x/src/main/java/io/reactivex/rxjava3/annotations/Beta.java +[experimental source link]: https://github.com/ReactiveX/RxJava/blob/3.x/src/main/java/io/reactivex/rxjava3/annotations/Experimental.java diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..10035743316 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,7 @@ +# Security Policy + +If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. + +Please disclose it at [security advisory](https://github.com/ReactiveX/RxJava/security/advisories/new). + +This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure. diff --git a/build.gradle b/build.gradle index f21e95925a1..8bcfddb7175 100644 --- a/build.gradle +++ b/build.gradle @@ -1,76 +1,39 @@ -buildscript { - - // Dependency versions - // --------------------------------------- - - ext.reactiveStreamsVersion = "1.0.3" - ext.junitVersion = "4.12" - ext.testNgVersion = "7.0.0" - ext.mockitoVersion = "3.2.4" - ext.jmhLibVersion = "1.21" - ext.jmhGradleVersion = "0.5.0" - ext.guavaVersion = "28.2-jre" - ext.jacocoVersion = "0.8.4" - ext.animalSnifferVersion = "1.5.0" - ext.licenseVersion = "0.15.0" - ext.bintrayVersion = "1.8.4" - ext.jfrogExtractorVersion = "4.12.0" - ext.bndVersion = "4.3.1" - ext.checkstyleVersion = "8.26" - - // -------------------------------------- - - repositories { - jcenter() - mavenCentral() - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "ru.vyarus:gradle-animalsniffer-plugin:$animalSnifferVersion" - classpath "gradle.plugin.com.hierynomus.gradle.plugins:license-gradle-plugin:$licenseVersion" - classpath "me.champeau.gradle:jmh-gradle-plugin:$jmhGradleVersion" - classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$bintrayVersion" - classpath "org.jfrog.buildinfo:build-info-extractor-gradle:$jfrogExtractorVersion" - classpath "biz.aQute.bnd:biz.aQute.bnd.gradle:$bndVersion" - } -} - -group = "io.reactivex.rxjava3" -ext.githubProjectName = "rxjava" - -version = project.properties["release.version"] - -def releaseTag = System.getenv("TRAVIS_TAG"); +plugins { + id("java-library") + id("checkstyle") + id("eclipse") + id("jacoco") + id("maven-publish") + id("ru.vyarus.animalsniffer") version "2.0.1" + id("me.champeau.jmh") version "0.7.3" + id("com.github.hierynomus.license") version "0.16.1" + id("biz.aQute.bnd.builder") version "6.4.0" + id("com.vanniktech.maven.publish") version "0.33.0" + id("org.beryx.jar") version "2.0.0" + id("signing") +} + +ext { + reactiveStreamsVersion = "1.0.4" + junitVersion = "4.13.2" + testNgVersion = "7.5" + mockitoVersion = "4.11.0" + jmhLibVersion = "1.21" + guavaVersion = "33.5.0-jre" +} + +def releaseTag = System.getenv("BUILD_TAG") if (releaseTag != null && !releaseTag.isEmpty()) { if (releaseTag.startsWith("v")) { - releaseTag = releaseTag.substring(1); + releaseTag = releaseTag.substring(1) } - version = releaseTag; - project.properties.put("release.version", releaseTag); + project.version = releaseTag - println("Releasing with version " + version); + logger.lifecycle("Releasing with version: " + project.version) } -description = "RxJava: Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM." - -apply plugin: "java-library" -apply plugin: "checkstyle" -apply plugin: "jacoco" -apply plugin: "ru.vyarus.animalsniffer" -apply plugin: "maven" -apply plugin: "me.champeau.gradle.jmh" -apply plugin: "com.github.hierynomus.license" -apply plugin: "com.jfrog.bintray" -apply plugin: "com.jfrog.artifactory" -apply plugin: "eclipse" - -sourceCompatibility = JavaVersion.VERSION_1_8 -targetCompatibility = JavaVersion.VERSION_1_8 - repositories { - mavenCentral() + mavenCentral() } dependencies { @@ -87,8 +50,27 @@ dependencies { testImplementation "com.google.guava:guava:$guavaVersion" } +def buildWith11 = System.getenv("BUILD_WITH_11") +java { + toolchain { + vendor = JvmVendorSpec.ADOPTIUM + if ("true".equals(buildWith11)) { + languageVersion = JavaLanguageVersion.of(11) + } else { + languageVersion = JavaLanguageVersion.of(8) + } + } + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType(JavaCompile) { + options.compilerArgs << "-parameters" +} + +apply from: file("gradle/javadoc_cleanup.gradle") + javadoc { - failOnError = false exclude "**/internal/**" exclude "**/test/**" exclude "**/perf/**" @@ -100,111 +82,57 @@ javadoc { options.addStringOption("top").value = "" options.addStringOption("doctitle").value = "" options.addStringOption("header").value = "" - options.stylesheetFile = new File(projectDir, "gradle/stylesheet.css"); + options.stylesheetFile = project.file("gradle/stylesheet.css") options.links( - "https://docs.oracle.com/javase/8/docs/api/", - "http://www.reactive-streams.org/reactive-streams-${reactiveStreamsVersion}-javadoc/" + "https://docs.oracle.com/javase/8/docs/api/", + "https://reactivex.io/RxJava/org.reactivestreams.javadoc/${reactiveStreamsVersion}/" ) + + finalizedBy javadocCleanup } animalsniffer { annotation = "io.reactivex.rxjava3.internal.util.SuppressAnimalSniffer" } -task sourcesJar(type: Jar, dependsOn: classes) { - classifier = "sources" - from sourceSets.main.allSource +moduleConfig { + moduleInfoPath = 'src/main/module/module-info.java' + multiReleaseVersion = 9 + version = project.version } -task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = "javadoc" - from javadoc.destinationDir -} - -artifacts { - archives jar - archives sourcesJar - archives javadocJar -} - -apply plugin: 'biz.aQute.bnd.builder' - jar { - bnd ('Bundle-Name': 'rxjava', - 'Bundle-Vendor': 'RxJava Contributors', - 'Bundle-Description': 'Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.', - 'Import-Package': '!org.junit,!junit.framework,!org.mockito.*,!org.testng.*,*', - 'Bundle-DocURL': 'https://github.com/ReactiveX/RxJava', - 'Eclipse-ExtensibleAPI': 'true', - 'Automatic-Module-Name': 'io.reactivex.rxjava3', - 'Export-Package': '!io.reactivex.rxjava3.internal.*, io.reactivex.rxjava3.*' + from('.') { + include 'LICENSE' + include 'COPYRIGHT' + into('META-INF/') + } + exclude("module-info.class") + + // Cover for bnd still not supporting MR Jars: https://github.com/bndtools/bnd/issues/2227 + bnd('-fixupmessages': '^Classes found in the wrong directory: \\\\{META-INF/versions/9/module-info\\\\.class=module-info}$') + bnd( + "Bundle-Name": "rxjava", + "Bundle-Vendor": "RxJava Contributors", + "Bundle-Description": "Reactive Extensions for the JVM - a library for composing asynchronous and event-based programs using observable sequences for the Java VM.", + "Import-Package": "!org.junit,!junit.framework,!org.mockito.*,!org.testng.*,*", + "Bundle-DocURL": "https://github.com/ReactiveX/RxJava", + "Eclipse-ExtensibleAPI": "true", + "Export-Package": "!io.reactivex.rxjava3.internal.*, io.reactivex.rxjava3.*", + "Bundle-SymbolicName": "io.reactivex.rxjava3.rxjava", + "Multi-Release": "true" ) } license { - header rootProject.file("HEADER") + header project.file("config/license/HEADER") ext.year = Calendar.getInstance().get(Calendar.YEAR) skipExistingHeaders true ignoreFailures true excludes(["**/*.md", "**/*.txt"]) } -apply plugin: "maven-publish" - -install { - repositories.mavenInstaller.pom.project { - name "RxJava" - description "Reactive Extensions for Java" - url "https://github.com/ReactiveX/RxJava" - licenses { - license { - name "The Apache Software License, Version 2.0" - url "http://www.apache.org/licenses/LICENSE-2.0.txt" - distribution "repo" - } - } - developers { - developer { - id "akarnokd" - name "David Karnok" - email "akarnokd@gmail.com" - } - } - scm { - connection "scm:git:git@github.com:ReactiveX/RxJava.git" - url "scm:git:git@github.com:ReactiveX/RxJava.git" - developerConnection "scm:git:git@github.com:ReactiveX/RxJava.git" - } - issueManagement { - system "github" - url "https://github.com/ReactiveX/RxJava/issues" - } - } -} - -publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact (sourcesJar) { - classifier = "sources" - } - } - } -} - -// Reactive-Streams as compile dependency -publishing.publications.all { - pom.withXml { - asNode().dependencies."*".findAll() { - it.scope.text() == "runtime" && project.configurations.compile.allDependencies.find { dep -> - dep.name == it.artifactId.text() - } - }.each { it.scope*.value = "compile"} - } -} - jmh { jmhVersion = jmhLibVersion humanOutputFile = null @@ -213,162 +141,79 @@ jmh { jvmArgsAppend = ["-Djmh.separateClasspathJAR=true"] if (project.hasProperty("jmh")) { - include = ".*" + project.jmh + ".*" - println("JMH: " + include); + includes = [".*" + project.jmh + ".*"] + logger.info("JMH: {}", includes) } +} +test { + maxHeapSize = "1200m" } -plugins.withType(EclipsePlugin) { - project.eclipse.classpath.plusConfigurations += [ configurations.jmh ] +task testNG(type: Test) { + useTestNG() } -test { - - testLogging { - // showing skipped occasionally should prevent CI timeout due to lack of standard output - events=["skipped", "failed"] // "started", "passed" - // showStandardStreams = true - exceptionFormat="full" +check.dependsOn testNG + +tasks.withType(Test) { + testLogging { + events = ["skipped", "failed"] + exceptionFormat = "full" debug.events = ["skipped", "failed"] - debug.exceptionFormat="full" + debug.exceptionFormat = "full" info.events = ["failed", "skipped"] - info.exceptionFormat="full" - + info.exceptionFormat = "full" + warn.events = ["failed", "skipped"] - warn.exceptionFormat="full" + warn.exceptionFormat = "full" } - maxHeapSize = "1200m" - if (System.getenv("CI") == null) { maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1 } } -task testng(type: Test) { - useTestNG() - testLogging { - events=["skipped", "failed"] - exceptionFormat="full" - - debug.events = ["skipped", "failed"] - debug.exceptionFormat="full" - - info.events = ["failed", "skipped"] - info.exceptionFormat="full" - - warn.events = ["failed", "skipped"] - warn.exceptionFormat="full" - } -} - -check.dependsOn testng - -jacoco { - toolVersion = jacocoVersion // See http://www.eclemma.org/jacoco/. -} - -task GCandMem(dependsOn: "check") doLast { - print("Memory usage before: ") - println(java.lang.management.ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed() / 1024.0 / 1024.0) - System.gc() - Thread.sleep(200) - print("Memory usage: ") - println(java.lang.management.ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed() / 1024.0 / 1024.0) -} - -task GCandMem2(dependsOn: "test") doLast { - print("Memory usage before: ") - println(java.lang.management.ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed() / 1024.0 / 1024.0) - System.gc() - Thread.sleep(200) - print("Memory usage: ") - println(java.lang.management.ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed() / 1024.0 / 1024.0) -} - -testng.dependsOn GCandMem2 - jacocoTestReport { + dependsOn test + dependsOn testNG + reports { - xml.enabled = true - html.enabled = true + xml.required.set(true) + csv.required.set(false) + html.required.set(true) } } -jacocoTestReport.dependsOn GCandMem - -build.dependsOn jacocoTestReport +check.dependsOn jacocoTestReport checkstyle { - configFile file("checkstyle.xml") - ignoreFailures = true - toolVersion = checkstyleVersion + configFile = project.file("config/checkstyle/checkstyle.xml") + configProperties = [ + "checkstyle.suppressions.file": project.file("config/checkstyle/suppressions.xml"), + "checkstyle.header.file" : project.file("config/license/HEADER_JAVA") + ] + checkstyleMain.exclude '**/module-info.java' } -if (rootProject.hasProperty("releaseMode")) { - - if ("branch".equals(rootProject.releaseMode)) { - // From https://github.com/ReactiveX/RxAndroid/blob/2.x/rxandroid/build.gradle#L94 - - println("ReleaseMode: " + rootProject.releaseMode); - artifactory { - contextUrl = "https://oss.jfrog.org" - - publish { - repository { - repoKey = "oss-snapshot-local" - - username = rootProject.bintrayUser - password = rootProject.bintrayKey - } - - defaults { - publishConfigs("archives") - } - } +if (project.hasProperty("releaseMode")) { + logger.lifecycle("ReleaseMode: {}", project.releaseMode) + + + if ("full" == project.releaseMode) { + signing { + if (project.hasProperty("SIGNING_PRIVATE_KEY") && project.hasProperty("SIGNING_PASSWORD")) { + useInMemoryPgpKeys(project.getProperty("SIGNING_PRIVATE_KEY"), project.getProperty("SIGNING_PASSWORD")) + sign(publishing.publications) + } } - - build.finalizedBy(artifactoryPublish) } + mavenPublishing { + // or when publishing to https://central.sonatype.com/ + publishToMavenCentral(com.vanniktech.maven.publish.SonatypeHost.CENTRAL_PORTAL) - if ("full".equals(rootProject.releaseMode)) { - // based on https://github.com/bintray/gradle-bintray-plugin - def rver = version; - - println("ReleaseMode: " + rootProject.releaseMode + " version " + rver); - - bintray { - user = rootProject.bintrayUser - key = rootProject.bintrayKey - configurations = ["archives"] - publish = true - pkg { - repo = "RxJava" - name = "RxJava" - userOrg = "reactivex" - labels = ["rxjava", "reactivex"] - licenses = ["Apache-2.0"] - vcsUrl = "https://github.com/ReactiveX/RxJava.git" - version { - name = rver - gpg { - sign = true - } - mavenCentralSync { - sync = true - user = rootProject.sonatypeUsername - password = rootProject.sonatypePassword - close = "1" - } - } - } - } - - build.finalizedBy(bintrayUpload) - } + // signAllPublications() + } } - -apply from: file("gradle/javadoc_cleanup.gradle") diff --git a/checkstyle.xml b/checkstyle.xml deleted file mode 100644 index 3e7ba879da5..00000000000 --- a/checkstyle.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 00000000000..05896aee126 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml new file mode 100644 index 00000000000..cf580e45e60 --- /dev/null +++ b/config/checkstyle/suppressions.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/HEADER b/config/license/HEADER similarity index 100% rename from HEADER rename to config/license/HEADER diff --git a/config/license/HEADER_JAVA b/config/license/HEADER_JAVA new file mode 100644 index 00000000000..d95b44938b5 --- /dev/null +++ b/config/license/HEADER_JAVA @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ diff --git a/docs/Additional-Reading.md b/docs/Additional-Reading.md index 85e7d47077e..4badd813085 100644 --- a/docs/Additional-Reading.md +++ b/docs/Additional-Reading.md @@ -3,7 +3,7 @@ A more complete and up-to-date list of resources can be found at the [reactivex. # Introducing Reactive Programming * [Introduction to Rx](http://www.introtorx.com/): a free, on-line book by Lee Campbell **(1.x)** * [The introduction to Reactive Programming you've been missing](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754) by Andre Staltz -* [Mastering Observables](http://docs.couchbase.com/developer/java-2.0/observables.html) from the Couchbase documentation **(1.x)** +* [Mastering Observables](https://docs.huihoo.com/couchbase/developer-guide/java-2.0/observables.html) from the Couchbase documentation **(1.x)** * [Reactive Programming in Java 8 With RxJava](http://pluralsight.com/training/Courses/TableOfContents/reactive-programming-java-8-rxjava), a course designed by Russell Elledge **(1.x)** * [33rd Degree Reactive Java](http://www.slideshare.net/tkowalcz/33rd-degree-reactive-java) by Tomasz Kowalczewski **(1.x)** * [What Every Hipster Should Know About Functional Reactive Programming](http://www.infoq.com/presentations/game-functional-reactive-programming) - Bodil Stokke demos the creation of interactive game mechanics in RxJS diff --git a/docs/Backpressure-(2.0).md b/docs/Backpressure-(2.0).md index 61361d21c4b..6b2f2860af5 100644 --- a/docs/Backpressure-(2.0).md +++ b/docs/Backpressure-(2.0).md @@ -172,7 +172,7 @@ If some of the values can be safely ignored, one can use the sampling (with time } ``` -Note hovewer that these operators only reduce the rate of value reception by the downstream and thus they may still lead to `MissingBackpressureException`. +Note however that these operators only reduce the rate of value reception by the downstream and thus they may still lead to `MissingBackpressureException`. ## onBackpressureBuffer() @@ -229,7 +229,7 @@ Note that the last two strategies cause discontinuity in the stream as they drop ## onBackpressureDrop() -Whenever the downstream is not ready to receive values, this operator will drop that elemenet from the sequence. One can think of it as a 0 capacity `onBackpressureBuffer` with strategy `ON_OVERFLOW_DROP_LATEST`. +Whenever the downstream is not ready to receive values, this operator will drop that element from the sequence. One can think of it as a 0 capacity `onBackpressureBuffer` with strategy `ON_OVERFLOW_DROP_LATEST`. This operator is useful when one can safely ignore values from a source (such as mouse moves or current GPS location signals) as there will be more up-to-date values later on. diff --git a/docs/Backpressure.md b/docs/Backpressure.md index bfe90330bbb..8529ec0995b 100644 --- a/docs/Backpressure.md +++ b/docs/Backpressure.md @@ -20,7 +20,7 @@ Cold Observables are ideal for the reactive pull model of backpressure described Your first line of defense against the problems of over-producing Observables is to use some of the ordinary set of Observable operators to reduce the number of emitted items to a more manageable number. The examples in this section will show how you might use such operators to handle a bursty Observable like the one illustrated in the following marble diagram: -​ +​ By fine-tuning the parameters to these operators you can ensure that a slow-consuming observer is not overwhelmed by a fast-producing Observable. @@ -33,7 +33,7 @@ The following diagrams show how you could use each of these operators on the bur ### sample (or throttleLast) The `sample` operator periodically "dips" into the sequence and emits only the most recently emitted item during each dip: -​ +​ ```java Observable burstySampled = bursty.sample(500, TimeUnit.MILLISECONDS); ``` @@ -41,7 +41,7 @@ Observable burstySampled = bursty.sample(500, TimeUnit.MILLISECONDS); ### throttleFirst The `throttleFirst` operator is similar, but emits not the most recently emitted item, but the first item that was emitted after the previous "dip": -​ +​ ```java Observable burstyThrottled = bursty.throttleFirst(500, TimeUnit.MILLISECONDS); ``` @@ -49,7 +49,7 @@ Observable burstyThrottled = bursty.throttleFirst(500, TimeUnit.MILLISE ### debounce (or throttleWithTimeout) The `debounce` operator emits only those items from the source Observable that are not followed by another item within a specified duration: -​ +​ ```java Observable burstyDebounced = bursty.debounce(10, TimeUnit.MILLISECONDS); ``` @@ -64,14 +64,14 @@ The following diagrams show how you could use each of these operators on the bur You could, for example, close and emit a buffer of items from the bursty Observable periodically, at a regular interval of time: -​ +​ ```java Observable> burstyBuffered = bursty.buffer(500, TimeUnit.MILLISECONDS); ``` Or you could get fancy, and collect items in buffers during the bursty periods and emit them at the end of each burst, by using the `debounce` operator to emit a buffer closing indicator to the `buffer` operator: -​ +​ ```java // we have to multicast the original bursty Observable so we can use it // both as our source and as the source for our buffer closing selector: @@ -86,14 +86,14 @@ Observable> burstyBuffered = burstyMulticast.buffer(burstyDebounce `window` is similar to `buffer`. One variant of `window` allows you to periodically emit Observable windows of items at a regular interval of time: -​ +​ ```java Observable> burstyWindowed = bursty.window(500, TimeUnit.MILLISECONDS); ```` You could also choose to emit a new window each time you have collected a particular number of items from the source Observable: -​ +​ ```java Observable> burstyWindowed = bursty.window(5); ``` @@ -128,7 +128,7 @@ someObservable.subscribe(new Subscriber() { } @Override - public void onNext(t n) { + public void onNext(T n) { // do something with the emitted item "n" // request another item: request(1); @@ -158,18 +158,18 @@ For this to work, though, Observables _A_ and _B_ must respond correctly to the
onBackpressureBuffer
-
maintains a buffer of all emissions from the source Observable and emits them to downstream Subscribers according to the requests they generate

an experimental version of this operator (not available in RxJava 1.0) allows you to set the capacity of the buffer; applying this operator will cause the resulting Observable to terminate with an error if this buffer is overrun​
+
maintains a buffer of all emissions from the source Observable and emits them to downstream Subscribers according to the requests they generate

an experimental version of this operator (not available in RxJava 1.0) allows you to set the capacity of the buffer; applying this operator will cause the resulting Observable to terminate with an error if this buffer is overrun​
onBackpressureDrop
-
drops emissions from the source Observable unless there is a pending request from a downstream Subscriber, in which case it will emit enough items to fulfill the request
​
+
drops emissions from the source Observable unless there is a pending request from a downstream Subscriber, in which case it will emit enough items to fulfill the request
​
onBackpressureBlock (experimental, not in RxJava 1.0)
-
blocks the thread on which the source Observable is operating until such time as a Subscriber issues a request for items, and then unblocks the thread only so long as there are pending requests
+
blocks the thread on which the source Observable is operating until such time as a Subscriber issues a request for items, and then unblocks the thread only so long as there are pending requests
If you do not apply any of these operators to an Observable that does not support backpressure, _and_ if either you as the Subscriber or some operator between you and the Observable attempts to apply reactive pull backpressure, you will encounter a `MissingBackpressureException` which you will be notified of via your `onError()` callback. # Further reading -If the standard operators are providing the expected behavior, [one can write custom operators in RxJava](https://github.com/ReactiveX/RxJava/wiki/Implementing-custom-operators-(draft)). +If the standard operators aren't providing the expected behavior, [one can write custom operators in RxJava](https://github.com/ReactiveX/RxJava/wiki/Implementing-custom-operators-(draft)). # See also * [RxJava 0.20.0-RC1 release notes](https://github.com/ReactiveX/RxJava/releases/tag/0.20.0-RC1) diff --git a/docs/Blocking-Observable-Operators.md b/docs/Blocking-Observable-Operators.md index 64d6e1b40ab..fe2a640f497 100644 --- a/docs/Blocking-Observable-Operators.md +++ b/docs/Blocking-Observable-Operators.md @@ -18,7 +18,7 @@ To transform an `Observable` into a `BlockingObservable`, use the [`Observable.t > This documentation accompanies its explanations with a modified form of "marble diagrams." Here is how these marble diagrams represent Blocking Observables: - + #### see also: * javadoc: `BlockingObservable` diff --git a/docs/Conditional-and-Boolean-Operators.md b/docs/Conditional-and-Boolean-Operators.md index f7ed64ce343..e6d1358e318 100644 --- a/docs/Conditional-and-Boolean-Operators.md +++ b/docs/Conditional-and-Boolean-Operators.md @@ -1,21 +1,169 @@ This section explains operators with which you conditionally emit or transform Observables, or can do boolean evaluations of them: ### Conditional Operators -* [**`amb( )`**](http://reactivex.io/documentation/operators/amb.html) — given two or more source Observables, emits all of the items from the first of these Observables to emit an item -* [**`defaultIfEmpty( )`**](http://reactivex.io/documentation/operators/defaultifempty.html) — emit items from the source Observable, or emit a default item if the source Observable completes after emitting no items -* (`rxjava-computation-expressions`) [**`doWhile( )`**](http://reactivex.io/documentation/operators/repeat.html) — emit the source Observable's sequence, and then repeat the sequence as long as a condition remains true -* (`rxjava-computation-expressions`) [**`ifThen( )`**](http://reactivex.io/documentation/operators/defer.html) — only emit the source Observable's sequence if a condition is true, otherwise emit an empty or default sequence -* [**`skipUntil( )`**](http://reactivex.io/documentation/operators/skipuntil.html) — discard items emitted by a source Observable until a second Observable emits an item, then emit the remainder of the source Observable's items -* [**`skipWhile( )`**](http://reactivex.io/documentation/operators/skipwhile.html) — discard items emitted by an Observable until a specified condition is false, then emit the remainder -* (`rxjava-computation-expressions`) [**`switchCase( )`**](http://reactivex.io/documentation/operators/defer.html) — emit the sequence from a particular Observable based on the results of an evaluation -* [**`takeUntil( )`**](http://reactivex.io/documentation/operators/takeuntil.html) — emits the items from the source Observable until a second Observable emits an item or issues a notification -* [**`takeWhile( )` and `takeWhileWithIndex( )`**](http://reactivex.io/documentation/operators/takewhile.html) — emit items emitted by an Observable as long as a specified condition is true, then skip the remainder -* (`rxjava-computation-expressions`) [**`whileDo( )`**](http://reactivex.io/documentation/operators/repeat.html) — if a condition is true, emit the source Observable's sequence and then repeat the sequence as long as the condition remains true - -> (`rxjava-computation-expressions`) — indicates that this operator is currently part of the optional `rxjava-computation-expressions` package under `rxjava-contrib` and is not included with the standard RxJava set of operators + +### Outline + +- [`amb`](#all) +- [`defaultIfEmpty`](#defaultIfEmpty) +- [`skipUntil`](#skipUntil) +- [`skipWhile`](#skipWhile) +- [`takeUntil`](#takeUntil) +- [`takeWhile`](#takeUntil) + +## amb + +**Available in:** ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Flowable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Observable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Maybe`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Single`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Completable` + +**ReactiveX documentation:** [http://reactivex.io/documentation/operators/amb.html](http://reactivex.io/documentation/operators/amb.html) + +given two or more source Observables, emits all of the items from the first of these Observables to emit an item + +```java + Observable source1 = Observable.range(1, 5); + Observable source2 = Observable.range(6, 5); + Observable.amb(new ArrayList(Arrays.asList(source1, source2))) + .subscribe(next -> System.out.printf("next: %s\n", next), // onNext + throwable -> System.out.printf("error: %s\n", throwable), //onError + () -> System.out.println("Completed") //onComplete + ); +``` +## defaultIfEmpty + +**Available in:** ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Flowable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Observable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Maybe`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Single`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Completable` + +**ReactiveX documentation:** [http://reactivex.io/documentation/operators/defaultifempty.html](http://reactivex.io/documentation/operators/defaultifempty.html) + +emit items from the source Observable, or emit a default item if the source Observable completes after emitting no items + +```java + Observable.empty().defaultIfEmpty(1).blockingSubscribe(next -> System.out.printf("next: %s\n", next), // onNext + throwable -> System.out.printf("error: %s", throwable), //onError + () -> System.out.println("Completed") //onComplete + ); +``` + +## skipUntil + +**Available in:** ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Flowable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Observable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Maybe`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Single`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Completable` + +**ReactiveX documentation:** [http://reactivex.io/documentation/operators/skipuntil.html](http://reactivex.io/documentation/operators/skipuntil.html) + +discard items emitted by a source Observable until a second Observable emits an item, then emit the remainder of the source Observable's items + +```java +Observable observable1 = Observable.range(1, 10).doOnNext(next -> Thread.sleep(1000)); + +observable1.skipUntil(Observable.timer(3, TimeUnit.SECONDS)) + .subscribe(next -> System.out.printf("next: %s\n", next), // onNext + throwable -> System.out.printf("error: %s", throwable), //onError + () -> System.out.println("Completed") //onComplete + ); +``` +## skipWhile + +**Available in:** ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Flowable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Observable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Maybe`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Single`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Completable` + +**ReactiveX documentation:** [http://reactivex.io/documentation/operators/skipwhile.html](http://reactivex.io/documentation/operators/skipwhile.html) + +discard items emitted by an Observable until a specified condition is false, then emit the remainder + +```java +Observable.range(1, 10).skipWhile(next -> next < 5) + .subscribe(next -> System.out.printf("next: %s\n", next), // onNext + throwable -> System.out.printf("error: %s", throwable), //onError + () -> System.out.println("Completed") //onComplete + ); +``` + +## takeUntil + +**Available in:** ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Flowable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Observable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Maybe`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Single`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Completable` + +**ReactiveX documentation:** [http://reactivex.io/documentation/operators/takeuntil.html](http://reactivex.io/documentation/operators/takeuntil.html) + +emits the items from the source Observable until a second Observable emits an item or issues a notification + +```java +Observable.range(1, 10).takeUntil(value -> value >= 5) + .subscribe(next -> System.out.printf("next: %s\n", next), // onNext + throwable -> System.out.printf("error: %s", throwable), //onError + () -> System.out.println("Completed") //onComplete + ); +``` + +## takeWhile + +**Available in:** ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Flowable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Observable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Maybe`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Single`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Completable` + +**ReactiveX documentation:** [http://reactivex.io/documentation/operators/takewhile.html](http://reactivex.io/documentation/operators/takewhile.html) + +emit items emitted by an Observable as long as a specified condition is true, then skip the remainder + +```java + Observable.range(1, 10).takeWhile(value -> value <= 5) + .subscribe(next -> System.out.printf("next: %s\n", next), // onNext + throwable -> System.out.printf("error: %s", throwable), //onError + () -> System.out.println("Completed") //onComplete + ); +``` ### Boolean Operators -* [**`all( )`**](http://reactivex.io/documentation/operators/all.html) — determine whether all items emitted by an Observable meet some criteria -* [**`contains( )`**](http://reactivex.io/documentation/operators/contains.html) — determine whether an Observable emits a particular item or not -* [**`exists( )` and `isEmpty( )`**](http://reactivex.io/documentation/operators/contains.html) — determine whether an Observable emits any items or not -* [**`sequenceEqual( )`**](http://reactivex.io/documentation/operators/sequenceequal.html) — test the equality of the sequences emitted by two Observables + +### Outline + +- [`all`](#all) +- [`contains`](#contains) +- [`isEmpty`](#isEmpty) +- [`sequenceEqual`](#sequenceEqual) + +## all +**Available in:** ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Flowable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Observable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Maybe`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Single`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Completable` + +**ReactiveX documentation:** [http://reactivex.io/documentation/operators/all.html](http://reactivex.io/documentation/operators/all.html) + +determine whether all items emitted by an Observable meet some criteria + +```java +Flowable.range(0,10).doOnNext(next -> System.out.println(next)).all(integer -> integer<10). + blockingSubscribe(success->System.out.println("Success: "+success)); +``` + +## contains +**Available in:** ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Flowable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Observable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Maybe`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Single`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Completable` + +**ReactiveX documentation:** [http://reactivex.io/documentation/operators/contains.html](http://reactivex.io/documentation/operators/contains.html) + +determine whether an Observable emits a particular item or not + +```java +Flowable.range(1,10).doOnNext(next->System.out.println(next)) + .contains(4).blockingSubscribe(contains->System.out.println("contains: "+contains)); +``` + +## isEmpty +**Available in:** ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Flowable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Observable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Maybe`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Single`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) `Completable` + +**ReactiveX documentation:** [http://reactivex.io/documentation/operators/contains.html](http://reactivex.io/documentation/operators/contains.html) + +determine whether the source Publisher is empty + +```java +Flowable.empty().isEmpty().subscribe(isEmpty -> System.out.printf("isEmpty: %s", isEmpty)); +``` + +## sequenceEqual +**Available in:** ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Flowable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Observable`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Maybe`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Single`, ![image](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png) `Completable` + +**ReactiveX documentation:** [http://reactivex.io/documentation/operators/sequenceequal.html](http://reactivex.io/documentation/operators/sequenceequal.html) + +test the equality of the sequences emitted by two Observables + +```java +Flowable flowable1 = Flowable.range(1,3).doOnNext(next-> System.out.print("flowable1: "+next + " ")); + +Flowable flowable2 = Flowable.range(1,3).doOnNext(next-> System.out.println("flowable2: "+next)); + +Flowable.sequenceEqual(Flowable.fromPublisher(flowable1),Flowable.fromPublisher(flowable2)) + .blockingSubscribe(sequenceEqual->System.out.println("sequenceEqual: "+sequenceEqual)); +``` diff --git a/docs/Connectable-Observable-Operators.md b/docs/Connectable-Observable-Operators.md index a0485475296..157ded821b1 100644 --- a/docs/Connectable-Observable-Operators.md +++ b/docs/Connectable-Observable-Operators.md @@ -7,25 +7,22 @@ This section explains the [`ConnectableObservable`](http://reactivex.io/RxJava/j A Connectable Observable resembles an ordinary Observable, except that it does not begin emitting items when it is subscribed to, but only when its `connect()` method is called. In this way you can wait for all intended Subscribers to subscribe to the Observable before the Observable begins emitting items. - + The following example code shows two Subscribers subscribing to the same Observable. In the first case, they subscribe to an ordinary Observable; in the second case, they subscribe to a Connectable Observable that only connects after both Subscribers subscribe. Note the difference in the output: **Example #1:** -```groovy -def firstMillion = Observable.range( 1, 1000000 ).sample(7, java.util.concurrent.TimeUnit.MILLISECONDS); +```java +Observable firstMillion = Observable.range(1, 1000000).sample(7, java.util.concurrent.TimeUnit.MILLISECONDS); -firstMillion.subscribe( - { println("Subscriber #1:" + it); }, // onNext - { println("Error: " + it.getMessage()); }, // onError - { println("Sequence #1 complete"); } // onCompleted -); - -firstMillion.subscribe( - { println("Subscriber #2:" + it); }, // onNext - { println("Error: " + it.getMessage()); }, // onError - { println("Sequence #2 complete"); } // onCompleted -); +firstMillion.subscribe(next -> System.out.println("Subscriber #1: " + next), // onNext + throwable -> System.out.println("Error: " + throwable), // onError + () -> System.out.println("Sequence #1 complete") // onComplete + ); +firstMillion.subscribe(next -> System.out.println("Subscriber #2: " + next), // onNext + throwable -> System.out.println("Error: " + throwable), // onError + () -> System.out.println("Sequence #2 complete") // onComplete + ); ``` ``` Subscriber #1:211128 @@ -40,20 +37,18 @@ Subscriber #2:826996 Sequence #2 complete ``` **Example #2:** -```groovy -def firstMillion = Observable.range( 1, 1000000 ).sample(7, java.util.concurrent.TimeUnit.MILLISECONDS).publish(); +```java +ConnectableObservable firstMillion = Observable.range(1, 1000000).sample(7, java.util.concurrent.TimeUnit.MILLISECONDS).publish(); -firstMillion.subscribe( - { println("Subscriber #1:" + it); }, // onNext - { println("Error: " + it.getMessage()); }, // onError - { println("Sequence #1 complete"); } // onCompleted -); +firstMillion.subscribe(next -> System.out.println("Subscriber #1: " + next), // onNext + throwable -> System.out.println("Error: " + throwable), // onError + () -> System.out.println("Sequence #1 complete") // onComplete + ); -firstMillion.subscribe( - { println("Subscriber #2:" + it); }, // onNext - { println("Error: " + it.getMessage()); }, // onError - { println("Sequence #2 complete"); } // onCompleted -); +firstMillion.subscribe(next -> System.out.println("Subscriber #2: " + next), // onNext + throwable -> System.out.println("Error: " + throwable), // onError + () -> System.out.println("Sequence #2 complete") // onComplete + ); firstMillion.connect(); ``` diff --git a/docs/Filtering-Observables.md b/docs/Filtering-Observables.md index 620800dc8cd..512b69ba8a1 100644 --- a/docs/Filtering-Observables.md +++ b/docs/Filtering-Observables.md @@ -259,7 +259,7 @@ firstOrError.subscribe( **ReactiveX documentation:** [http://reactivex.io/documentation/operators/ignoreelements.html](http://reactivex.io/documentation/operators/ignoreelements.html) -Ignores the single item emitted by a `Single` or `Maybe` source, and returns a `Completable` that signals only the error or completion event from the the source. +Ignores the single item emitted by a `Single` or `Maybe` source, and returns a `Completable` that signals only the error or completion event from the source. ### ignoreElement example diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index fb9baa47dd7..69b69a8ca61 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -1,20 +1,20 @@ ## Getting Binaries -You can find binaries and dependency information for Maven, Ivy, Gradle, SBT, and others at [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Cg%3A"io.reactivex.rxjava2"%20AND%20"rxjava2"). +You can find binaries and dependency information for Maven, Ivy, Gradle, SBT, and others at [http://search.maven.org](https://search.maven.org/search?q=g:io.reactivex.rxjava3%20AND%20rxjava). Example for Maven: ```xml - io.reactivex.rxjava2 + io.reactivex.rxjava3 rxjava - 2.2.0 + 3.0.4 ``` and for Ivy: ```xml - + ``` and for SBT: @@ -22,12 +22,12 @@ and for SBT: ```scala libraryDependencies += "io.reactivex" %% "rxscala" % "0.26.5" -libraryDependencies += "io.reactivex.rxjava2" % "rxjava" % "2.2.0" +libraryDependencies += "io.reactivex.rxjava3" % "rxjava" % "3.0.4" ``` and for Gradle: ```groovy -compile 'io.reactivex.rxjava2:rxjava:2.2.0' +implementation 'io.reactivex.rxjava3:rxjava:3.0.4' ``` If you need to download the jars instead of using a build system, create a Maven `pom` file like this with the desired version: @@ -38,17 +38,17 @@ If you need to download the jars instead of using a build system, create a Maven xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - io.reactivex.rxjava2 + io.reactivex.rxjava3 rxjava - 2.2.0 + 3.0.4 RxJava Reactive Extensions for Java https://github.com/ReactiveX/RxJava - io.reactivex.rxjava2 + io.reactivex.rxjava3 rxjava - 2.2.0 + 3.0.4 @@ -66,18 +66,21 @@ You need Java 6 or later. ### Snapshots -Snapshots are available via [JFrog](https://oss.jfrog.org/libs-snapshot/io/reactivex/rxjava2/rxjava/): +Snapshots after May 1st, 2021 are available via https://oss.sonatype.org/content/repositories/snapshots/io/reactivex/rxjava3/rxjava/ ```groovy repositories { - maven { url 'https://oss.jfrog.org/libs-snapshot' } + maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } } dependencies { - compile 'io.reactivex.rxjava2:rxjava:2.2.0-SNAPSHOT' + implementation 'io.reactivex.rxjava3:rxjava:3.0.0-SNAPSHOT' } ``` +JavaDoc snapshots are available at http://reactivex.io/RxJava/3.x/javadoc/snapshot + + ## Building To check out and build the RxJava source, issue the following commands: diff --git a/docs/How-To-Use-RxJava.md b/docs/How-To-Use-RxJava.md index ad309496b93..41a46bb75de 100644 --- a/docs/How-To-Use-RxJava.md +++ b/docs/How-To-Use-RxJava.md @@ -285,7 +285,7 @@ onNext => value_14_xform Here is a marble diagram that illustrates this transformation: - + This next example, in Clojure, consumes three asynchronous Observables, including a dependency from one to another, and emits a single response item by combining the items emitted by each of the three Observables with the [`zip`](http://reactivex.io/documentation/operators/zip.html) operator and then transforming the result with [`map`](http://reactivex.io/documentation/operators/map.html): @@ -333,7 +333,7 @@ The response looks like this: And here is a marble diagram that illustrates how that code produces that response: - + The following example, in Groovy, comes from [Ben Christensen’s QCon presentation on the evolution of the Netflix API](https://speakerdeck.com/benjchristensen/evolution-of-the-netflix-api-qcon-sf-2013). It combines two Observables with the [`merge`](http://reactivex.io/documentation/operators/merge.html) operator, then uses the [`reduce`](http://reactivex.io/documentation/operators/reduce.html) operator to construct a single item out of the resulting sequence, then transforms that item with [`map`](http://reactivex.io/documentation/operators/map.html) before emitting it: @@ -350,7 +350,7 @@ public Observable getVideoSummary(APIVideo video) { And here is a marble diagram that illustrates how that code uses the [`reduce`](http://reactivex.io/documentation/operators/reduce.html) operator to bring the results from multiple Observables together in one structure: - + ## Error Handling diff --git a/docs/Operator-Matrix.md b/docs/Operator-Matrix.md new file mode 100644 index 00000000000..afeb8e4182c --- /dev/null +++ b/docs/Operator-Matrix.md @@ -0,0 +1,359 @@ +Operator | ![Flowable](https://raw.github.com/wiki/ReactiveX/RxJava/images/opmatrix-flowable.png) | ![Observable](https://raw.github.com/wiki/ReactiveX/RxJava/images/opmatrix-observable.png) | ![Maybe](https://raw.github.com/wiki/ReactiveX/RxJava/images/opmatrix-maybe.png) | ![Single](https://raw.github.com/wiki/ReactiveX/RxJava/images/opmatrix-single.png) | ![Completable](https://raw.github.com/wiki/ReactiveX/RxJava/images/opmatrix-completable.png) | +-----|---|---|---|---|---| +`all`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([1](#notes-1))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([1](#notes-1))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`amb`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`ambArray`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`ambWith`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`andThen`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([3](#notes-3))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([3](#notes-3))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([3](#notes-3))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([3](#notes-3))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`any`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([1](#notes-1))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([1](#notes-1))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`blockingAwait`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([4](#notes-4))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([4](#notes-4))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([5](#notes-5))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([5](#notes-5))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`blockingFirst`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([7](#notes-7))| +`blockingForEach`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([8](#notes-8))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([8](#notes-8))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([8](#notes-8))| +`blockingGet`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([4](#notes-4))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([4](#notes-4))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([7](#notes-7))| +`blockingIterable`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([7](#notes-7))| +`blockingLast`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([7](#notes-7))| +`blockingLatest`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([7](#notes-7))| +`blockingMostRecent`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([7](#notes-7))| +`blockingNext`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([7](#notes-7))| +`blockingSingle`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([7](#notes-7))| +`blockingStream`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([6](#notes-6))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([7](#notes-7))| +`blockingSubscribe`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`buffer`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([9](#notes-9))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([10](#notes-10))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([11](#notes-11))| +`cache`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`cacheWithInitialCapacity`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([12](#notes-12))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([12](#notes-12))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([12](#notes-12))| +`cast`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`collect`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([13](#notes-13))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([14](#notes-14))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([15](#notes-15))| +`collectInto`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([13](#notes-13))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([14](#notes-14))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([15](#notes-15))| +`combineLatest`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([16](#notes-16))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([16](#notes-16))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([17](#notes-17))| +`combineLatestArray`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([18](#notes-18))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([18](#notes-18))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([19](#notes-19))| +`combineLatestArrayDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([18](#notes-18))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([18](#notes-18))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([20](#notes-20))| +`combineLatestDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([16](#notes-16))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([16](#notes-16))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([21](#notes-21))| +`complete`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([22](#notes-22))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([22](#notes-22))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([22](#notes-22))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([23](#notes-23))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`compose`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`concat`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`concatArray`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`concatArrayDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`concatArrayEager`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([24](#notes-24))| +`concatArrayEagerDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([25](#notes-25))| +`concatDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`concatEager`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([26](#notes-26))| +`concatEagerDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([27](#notes-27))| +`concatMap`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`concatMapCompletable`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`concatMapCompletableDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([29](#notes-29))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([29](#notes-29))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`concatMapDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([30](#notes-30))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([30](#notes-30))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`concatMapEager`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([31](#notes-31))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([31](#notes-31))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`concatMapEagerDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([31](#notes-31))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([31](#notes-31))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`concatMapIterable`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([32](#notes-32))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([32](#notes-32))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`concatMapMaybe`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([33](#notes-33))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`concatMapMaybeDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([34](#notes-34))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([34](#notes-34))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`concatMapSingle`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([35](#notes-35))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`concatMapSingleDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([36](#notes-36))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([36](#notes-36))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`concatMapStream`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([37](#notes-37))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([37](#notes-37))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`concatWith`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`contains`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`count`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([38](#notes-38))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([39](#notes-39))| +`create`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`debounce`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([40](#notes-40))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([40](#notes-40))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`defaultIfEmpty`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([23](#notes-23))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([42](#notes-42))| +`defer`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`delay`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`delaySubscription`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`dematerialize`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`distinct`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([43](#notes-43))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([43](#notes-43))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`distinctUntilChanged`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([43](#notes-43))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([43](#notes-43))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`doAfterNext`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([44](#notes-44))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([44](#notes-44))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`doAfterSuccess`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([45](#notes-45))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([45](#notes-45))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`doAfterTerminate`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`doFinally`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`doOnCancel`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([46](#notes-46))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([46](#notes-46))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([46](#notes-46))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([46](#notes-46))| +`doOnComplete`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([47](#notes-47))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`doOnDispose`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([48](#notes-48))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`doOnEach`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([49](#notes-49))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([49](#notes-49))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`doOnError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`doOnEvent`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([50](#notes-50))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([50](#notes-50))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`doOnLifecycle`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`doOnNext`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([51](#notes-51))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([51](#notes-51))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`doOnRequest`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))| +`doOnSubscribe`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`doOnSuccess`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([53](#notes-53))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([53](#notes-53))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`doOnTerminate`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`elementAt`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([54](#notes-54))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([55](#notes-55))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`elementAtOrError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([56](#notes-56))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([55](#notes-55))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`empty`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([23](#notes-23))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([57](#notes-57))| +`error`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`filter`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`first`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([58](#notes-58))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([59](#notes-59))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([42](#notes-42))| +`firstElement`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([61](#notes-61))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`firstOrError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([61](#notes-61))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([62](#notes-62))| +`firstOrErrorStage`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([64](#notes-64))| +`firstStage`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))| +`flatMap`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`flatMapCompletable`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`flatMapIterable`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([32](#notes-32))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([32](#notes-32))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`flatMapMaybe`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([65](#notes-65))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`flatMapObservable`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([66](#notes-66))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([67](#notes-67))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`flatMapPublisher`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([67](#notes-67))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([68](#notes-68))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`flatMapSingle`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([65](#notes-65))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`flatMapStream`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([37](#notes-37))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([37](#notes-37))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`flattenAsFlowable`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([69](#notes-69))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([69](#notes-69))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`flattenAsObservable`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([69](#notes-69))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([69](#notes-69))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`flattenStreamAsFlowable`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([70](#notes-70))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([70](#notes-70))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`flattenStreamAsObservable`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([70](#notes-70))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([70](#notes-70))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`forEach`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([71](#notes-71))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([71](#notes-71))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([71](#notes-71))| +`forEachWhile`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([71](#notes-71))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([71](#notes-71))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([71](#notes-71))| +`fromAction`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([23](#notes-23))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`fromArray`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([72](#notes-72))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([73](#notes-73))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([74](#notes-74))| +`fromCallable`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`fromCompletable`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([75](#notes-75))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([76](#notes-76))| +`fromCompletionStage`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`fromFuture`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`fromIterable`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([72](#notes-72))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([73](#notes-73))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([74](#notes-74))| +`fromMaybe`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([76](#notes-76))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`fromObservable`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([76](#notes-76))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`fromOptional`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([73](#notes-73))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([74](#notes-74))| +`fromPublisher`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`fromRunnable`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([23](#notes-23))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`fromSingle`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([76](#notes-76))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`fromStream`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([72](#notes-72))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([73](#notes-73))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([74](#notes-74))| +`fromSupplier`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`generate`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([77](#notes-77))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([77](#notes-77))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([77](#notes-77))| +`groupBy`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([78](#notes-78))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([78](#notes-78))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([79](#notes-79))| +`groupJoin`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([78](#notes-78))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([78](#notes-78))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([80](#notes-80))| +`hide`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`ignoreElement`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([81](#notes-81))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([81](#notes-81))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`ignoreElements`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([82](#notes-82))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([82](#notes-82))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`interval`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([83](#notes-83))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([83](#notes-83))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([83](#notes-83))| +`intervalRange`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([83](#notes-83))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([83](#notes-83))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([83](#notes-83))| +`isEmpty`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([59](#notes-59))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`join`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([84](#notes-84))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([84](#notes-84))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([80](#notes-80))| +`just`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`last`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([58](#notes-58))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([59](#notes-59))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([42](#notes-42))| +`lastElement`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([61](#notes-61))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`lastOrError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([61](#notes-61))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([62](#notes-62))| +`lastOrErrorStage`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([64](#notes-64))| +`lastStage`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))| +`lift`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`map`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`mapOptional`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`materialize`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`merge`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`mergeArray`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`mergeArrayDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`mergeDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`mergeWith`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`never`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`observeOn`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`ofType`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([85](#notes-85))| +`onBackpressureBuffer`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))| +`onBackpressureDrop`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))| +`onBackpressureLatest`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))| +`onErrorComplete`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`onErrorResumeNext`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`onErrorResumeWith`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`onErrorReturn`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`onErrorReturnItem`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`onTerminateDetach`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`parallel`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([86](#notes-86))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([86](#notes-86))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([86](#notes-86))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([86](#notes-86))| +`publish`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([87](#notes-87))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([88](#notes-88))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([89](#notes-89))| +`range`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([90](#notes-90))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([90](#notes-90))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([74](#notes-74))| +`rangeLong`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([90](#notes-90))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([90](#notes-90))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([74](#notes-74))| +`rebatchRequests`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([52](#notes-52))| +`reduce`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([91](#notes-91))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([91](#notes-91))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([92](#notes-92))| +`reduceWith`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([91](#notes-91))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([91](#notes-91))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([92](#notes-92))| +`repeat`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`repeatUntil`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`repeatWhen`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`replay`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([87](#notes-87))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([88](#notes-88))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([89](#notes-89))| +`retry`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`retryUntil`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`retryWhen`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`safeSubscribe`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`sample`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`scan`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([91](#notes-91))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([91](#notes-91))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([92](#notes-92))| +`scanWith`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([91](#notes-91))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([91](#notes-91))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([92](#notes-92))| +`sequenceEqual`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`serialize`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([93](#notes-93))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([93](#notes-93))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([93](#notes-93))| +`share`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([87](#notes-87))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([88](#notes-88))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([89](#notes-89))| +`single`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([58](#notes-58))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([59](#notes-59))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([42](#notes-42))| +`singleElement`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([61](#notes-61))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`singleOrError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([61](#notes-61))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([62](#notes-62))| +`singleOrErrorStage`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([64](#notes-64))| +`singleStage`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([63](#notes-63))| +`skip`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))| +`skipLast`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))| +`skipUntil`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([94](#notes-94))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([94](#notes-94))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([94](#notes-94))| +`skipWhile`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([95](#notes-95))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([95](#notes-95))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`sorted`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([78](#notes-78))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([78](#notes-78))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([78](#notes-78))| +`startWith`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`startWithArray`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([96](#notes-96))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([96](#notes-96))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([96](#notes-96))| +`startWithItem`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([97](#notes-97))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([97](#notes-97))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([97](#notes-97))| +`startWithIterable`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([98](#notes-98))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([98](#notes-98))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([98](#notes-98))| +`subscribe`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`subscribeOn`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`subscribeWith`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`switchIfEmpty`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([23](#notes-23))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([99](#notes-99))| +`switchMap`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`switchMapCompletable`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`switchMapCompletableDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`switchMapDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`switchMapMaybe`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`switchMapMaybeDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`switchMapSingle`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`switchMapSingleDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([100](#notes-100))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([28](#notes-28))| +`switchOnNext`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`switchOnNextDelayError`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`take`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))| +`takeLast`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([60](#notes-60))| +`takeUntil`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`takeWhile`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([95](#notes-95))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([95](#notes-95))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([2](#notes-2))| +`test`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`throttleFirst`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([40](#notes-40))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([40](#notes-40))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`throttleLast`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([40](#notes-40))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([40](#notes-40))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`throttleLatest`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([40](#notes-40))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([40](#notes-40))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`throttleWithTimeout`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([40](#notes-40))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([40](#notes-40))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`timeInterval`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`timeout`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`timer`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`timestamp`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([41](#notes-41))| +`to`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`toCompletionStage`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([101](#notes-101))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([101](#notes-101))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`toFlowable`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([102](#notes-102))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`toFuture`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`toList`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([13](#notes-13))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([14](#notes-14))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([15](#notes-15))| +`toMap`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([13](#notes-13))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([14](#notes-14))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([15](#notes-15))| +`toMaybe`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([103](#notes-103))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([103](#notes-103))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([102](#notes-102))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`toMultimap`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([13](#notes-13))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([14](#notes-14))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([15](#notes-15))| +`toObservable`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([102](#notes-102))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`toSingle`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([104](#notes-104))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([104](#notes-104))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([102](#notes-102))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`toSingleDefault`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([105](#notes-105))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([105](#notes-105))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([106](#notes-106))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([102](#notes-102))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`toSortedList`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([13](#notes-13))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([14](#notes-14))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([15](#notes-15))| +`unsafeCreate`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`unsubscribeOn`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`using`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`window`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([107](#notes-107))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([108](#notes-108))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([109](#notes-109))| +`withLatestFrom`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([16](#notes-16))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([16](#notes-16))|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([17](#notes-17))| +`wrap`|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([110](#notes-110))|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)| +`zip`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([111](#notes-111))| +`zipArray`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([112](#notes-112))| +`zipWith`|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)|![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png) ([113](#notes-113))| +**237 operators** | **216** | **210** | **118** | **108** | **84** | + +#### Notes +1 Use [`contains()`](#contains).
+2 Always empty.
+3 Use [`concatWith`](#concatWith).
+4 Use [`blockingFirst()`](#blockingFirst), [`blockingSingle()`](#blockingSingle) or [`blockingLast()`](#blockingLast).
+5 Use [`blockingGet()`](#blockingGet).
+6 At most one element to get. Use [`blockingGet()`](#blockingGet).
+7 No elements to get. Use [`blockingAwait()`](#blockingAwait).
+8 Use [`blockingSubscribe()`](#blockingSubscribe)
+9 Use [`map()`](#map) and [`switchIfEmpty()`](#switchIfEmpty) to transform into a list/collection.
+10 Use [`map()`](#map) to transform into a list/collection.
+11 Always empty. Use [`andThen()`](#andThen) to bring in a list/collection.
+12 At most one element to store. Use [`cache()`](#cache).
+13 At most one element to collect. Use [`map()`](#map) and [`switchIfEmpty()`](#switchIfEmpty) to transform into a list/collection.
+14 One element to collect. Use [`map()`](#map) to transform into a list/collection.
+15 Always empty. Use [`andThen()`](#andThen) to bring in a collection.
+16 At most one element per source. Use [`zip()`](#zip).
+17 Always empty. Use [`merge()`](#merge).
+18 At most one element per source. Use [`zipArray()`](#zipArray).
+19 Always empty. Use [`mergeArray()`](#mergeArray).
+20 Always empty. Use [`mergeArrayDelayError()`](#mergeArrayDelayError).
+21 Always empty. Use [`mergeDelayError()`](#mergeDelayError).
+22 Use [`empty()`](#empty).
+23 Never empty.
+24 No items to keep ordered. Use [`mergeArray()`](#mergeArray).
+25 No items to keep ordered. Use [`mergeArrayDelayError()`](#mergeArrayDelayError).
+26 No items to keep ordered. Use [`merge()`](#merge).
+27 No items to keep ordered. Use [`mergeDelayError()`](#mergeDelayError).
+28 Always empty thus no items to map.
+29 Either the upstream fails (thus no inner) or the mapped-in source, but never both. Use [`concatMapCompletable`](#concatMapCompletable).
+30 Either the upstream fails (thus no inner) or the mapped-in source, but never both. Use [`concatMap`](#concatMap).
+31 At most one item to map. Use [`concatMap()`](#concatMap).
+32 At most one item. Use [`flattenAsFlowable`](#flattenAsFlowable) or [`flattenAsObservable`](#flattenAsObservable).
+33 Use [`concatMap`](#concatMap).
+34 Either the upstream fails (thus no inner) or the mapped-in source, but never both. Use [`concatMapMaybe`](#concatMapMaybe).
+35 Use [`concatMap()`](#concatMap).
+36 Either the upstream fails (thus no inner) or the mapped-in source, but never both. Use [`concatMapSingle`](#concatMapSingle).
+37 At most one item. Use [`flattenStreamAsFlowable`](#flattenStreamAsFlowable) or [`flattenStreamAsObservable`](#flattenStreamAsObservable).
+38 Never empty thus always 1.
+39 Always empty thus always 0.
+40 At most one item signaled so no subsequent items to work with.
+41 Always empty thus no items to work with.
+42 Always empty. Use [`andThen()`](#andThen) to chose the follow-up sequence.
+43 At most one item, always distinct.
+44 Different terminology. Use [`doAfterSuccess()`](#doAfterSuccess).
+45 Different terminology. Use [`doAfterNext()`](#doAfterNext).
+46 Different terminology. Use [`doOnDispose()`](#doOnDispose).
+47 Always succeeds or fails, there is no `onComplete` signal.
+48 Different terminology. Use [`doOnCancel()`](#doOnCancel).
+49 At most one item. Use [`doOnEvent()`](#doOnEvent).
+50 Use [`doOnEach()`](#doOnEach).
+51 Different terminology. Use [`doOnSuccess()`](#doOnSuccess).
+52 Backpressure related and not supported outside `Flowable`.
+53 Different terminology. Use [`doOnNext()`](#doOnNext).
+54 At most one item with index 0. Use [`defaultIfEmpty`](#defaultIfEmpty).
+55 Always one item with index 0.
+56 At most one item with index 0. Use [`toSingle`](#toSingle).
+57 Use [`complete()`](#complete).
+58 At most one item. Use [`defaultIfEmpty`](#defaultIfEmpty).
+59 Always one item.
+60 At most one item, would be no-op.
+61 Always one item, would be no-op.
+62 Always empty. Use [`andThen()`](#andThen) and [`error()`](#error).
+63 At most one item. Use [`toCompletionStage()`](#toCompletionStage).
+64 Always empty. Use [`andThen()`](#andThen), [`error()`](#error) and [`toCompletionStage()`](#toCompletionStage).
+65 Use [`flatMap()`](#flatMap).
+66 Not supported. Use [`flatMap`](#flatMap) and [`toFlowable()`](#toFlowable).
+67 Use [`flatMap`](#flatMap).
+68 Not supported. Use [`flatMap`](#flatMap) and [`toObservable()`](#toFlowable).
+69 Use [`flatMapIterable()`](#flatMapIterable).
+70 Use [`flatMapStream()`](#flatMapStream).
+71 Use [`subscribe()`](#subscribe).
+72 At most one item. Use [`just()`](#just) or [`empty()`](#empty).
+73 Always one item. Use [`just()`](#just).
+74 Always empty. Use [`complete()`](#complete).
+75 Always error.
+76 Use [`wrap()`](#wrap).
+77 Use [`fromSupplier()`](#fromSupplier).
+78 At most one item.
+79 Always empty thus no items to group.
+80 Always empty thus no items to join.
+81 Use [`ignoreElements()`](#ignoreElements).
+82 Use [`ignoreElement()`](#ignoreElement).
+83 At most one item. Use [`timer()`](#timer).
+84 At most one item. Use [`zip()`](#zip)
+85 Always empty thus no items to filter.
+86 Needs backpressure thus not supported outside `Flowable`.
+87 Connectable sources not supported outside `Flowable` and `Observable`. Use a `MaybeSubject`.
+88 Connectable sources not supported outside `Flowable` and `Observable`. Use a `SingleSubject`.
+89 Connectable sources not supported outside `Flowable` and `Observable`. Use a `ConnectableSubject`.
+90 At most one item. Use [`just()`](#just).
+91 At most one item. Use [`map()`](#map).
+92 Always empty thus no items to reduce.
+93 At most one signal type.
+94 At most one item. Use [`takeUntil()`](#takeUntil).
+95 At most one item. Use [`filter()`](#filter).
+96 Use [`startWith()`](#startWith) and [`fromArray()`](#fromArray) of `Flowable` or `Observable`.
+97 Use [`startWith()`](#startWith) and [`just()`](#just) of another reactive type.
+98 Use [`startWith()`](#startWith) and [`fromIterable()`](#fromArray) of `Flowable` or `Observable`.
+99 Always empty. Use [`defaultIfEmpty()`](#defaultIfEmpty).
+100 At most one item. Use [`flatMap()`](#flatMap).
+101 Use [`firstStage`](#firstStage), [`lastStage`](#lastStage) or [`singleStage`](#singleStage).
+102 Would be no-op.
+103 Use [`firstElement`](#firstElement), [`lastElement`](#lastElement) or [`singleElement`](#singleElement).
+104 Use [`firstOrError`](#firstOrError), [`lastOrError`](#lastOrError) or [`singleOrError`](#singleOrError).
+105 Use [`first`](#first), [`last`](#last) or [`single`](#single).
+106 Use [`defaultIfEmpty()`](#defaultIfEmpty).
+107 Use [`map()`](#map) and [`switchIfEmpty()`](#switchIfEmpty) to transform into a nested source.
+108 Use [`map()`](#map) to transform into a nested source.
+109 Always empty. Use [`andThen()`](#andThen) to bring in a nested source.
+110 Use [`fromPublisher()`](#fromPublisher).
+111 Use [`merge()`](#merge).
+112 Use [`mergeArray()`](#mergeArray).
+113 Use [`mergeWith()`](#mergeWith).
+ +#### Under development + +*Currently, all intended operators are implemented.* diff --git a/docs/Phantom-Operators.md b/docs/Phantom-Operators.md index 60da4a1a403..5193147a228 100644 --- a/docs/Phantom-Operators.md +++ b/docs/Phantom-Operators.md @@ -19,7 +19,7 @@ These operators have been proposed but are not part of the 1.0 release of RxJava ## chunkify( ) #### returns an iterable that periodically returns a list of items emitted by the source Observable since the last list - + The `chunkify( )` operator represents a blocking observable as an Iterable, that, each time you iterate over it, returns a list of items emitted by the source Observable since the previous iteration. These lists may be empty if there have been no such items emitted. @@ -27,7 +27,7 @@ The `chunkify( )` operator represents a blocking observable as an Iterable, th ## fromFuture( ) #### convert a Future into an Observable, but do not attempt to get the Future's value until a Subscriber subscribes - + The `fromFuture( )` method also converts a Future into an Observable, but it obtains this Future indirectly, by means of a function you provide. It creates the Observable immediately, but waits to call the function and to obtain the Future until a Subscriber subscribes to it. @@ -35,7 +35,7 @@ The `fromFuture( )` method also converts a Future into an Observable, but it o ## forEachFuture( ) #### create a futureTask that will invoke a specified function on each item emitted by an Observable - + The `forEachFuture( )` returns a `FutureTask` for each item emitted by the source Observable (or each item and each notification) that, when executed, will apply a function you specify to each such item (or item and notification). @@ -43,7 +43,7 @@ The `forEachFuture( )` returns a `FutureTask` for each item emitted by the sou ## forIterable( ) #### apply a function to the elements of an Iterable to create Observables which are then concatenated - + `forIterable( )` is similar to `from(Iterable )` but instead of the resulting Observable emitting the elements of the Iterable as its own emitted items, it applies a specified function to each of these elements to generate one Observable per element, and then concatenates the emissions of these Observables to be its own sequence of emitted items. @@ -58,7 +58,7 @@ If the a subscriber to the Observable that results when a Future is converted to ## generate( ) and generateAbsoluteTime( ) #### create an Observable that emits a sequence of items as generated by a function of your choosing - + The basic form of `generate( )` takes four parameters. These are `initialState` and three functions: `iterate( )`, `condition( )`, and `resultSelector( )`. `generate( )` uses these four parameters to generate an Observable sequence, which is its return value. It does so in the following way. @@ -66,7 +66,7 @@ The basic form of `generate( )` takes four parameters. These are `initialState There are also versions of `generate( )` that allow you to do the work of generating the sequence on a particular `Scheduler` and that allow you to set the time interval between emissions by applying a function to the current state. The `generateAbsoluteTime( )` allows you to control the time at which an item is emitted by applying a function to the state to get an absolute system clock time (rather than an interval from the previous emission). - + #### see also: * Introduction to Rx: Generate @@ -79,7 +79,7 @@ There are also versions of `generate( )` that allow you to do the work of gene This version of `groupBy` adds another parameter: an Observable that emits duration markers. When a duration marker is emitted by this Observable, any grouped Observables that have been opened are closed, and `groupByUntil( )` will create new grouped Observables for any subsequent emissions by the source Observable. -​ +​ Another variety of `groupByUntil( )` limits the number of groups that can be active at any particular time. If an item is emitted by the source Observable that would cause the number of groups to exceed this maximum, before the new group is emitted, one of the existing groups is closed (that is, the Observable it represents terminates by calling its Subscribers' `onCompleted` methods and then expires). @@ -101,7 +101,7 @@ To represent an Observable as a Connectable Observable, use the `multicast( )` ## onErrorFlatMap( ) #### instructs an Observable to emit a sequence of items whenever it encounters an error -​ +​ The `onErrorFlatMap( )` method is similar to `onErrorResumeNext( )` except that it does not assume the source Observable will correctly terminate when it issues an error. Because of this, after emitting its backup sequence of items, `onErrorFlatMap( )` relinquishes control of the emitted sequence back to the source Observable. If that Observable again issues an error, `onErrorFlatMap( )` will again emit its backup sequence. @@ -111,13 +111,13 @@ Because `onErrorFlatMap( )` is designed to work with pathological source Obser Note that you should apply `onErrorFlatMap( )` directly to the pathological source Observable, and not to that Observable after it has been modified by additional operators, as such operators may effectively renormalize the source Observable by unsubscribing from it immediately after it issues an error. Below, for example, is an illustration showing how `onErrorFlatMap( )` will respond to two error-generating Observables that have been merged by the `merge( )` operator. Note that it will *not* react to both errors generated by both Observables, but only to the single error passed along by `merge( )`: -​ +​ *** ## parallel( ) #### split the work done on the emissions from an Observable into multiple Observables each operating on its own parallel thread -​ +​ The `parallel( )` method splits an Observable into as many Observables as there are available processors, and does work in parallel on each of these Observables. `parallel( )` then merges the results of these parallel computations back into a single, well-behaved Observable sequence. @@ -127,7 +127,7 @@ streamOfItems.flatMap(item -> { itemToObservable(item).subscribeOn(Schedulers.io()); }); ``` -Kick off your work for each item inside [`flatMap`](Transforming-Observables#flatmap-concatmap-and-flatmapiterable) using [`subscribeOn`](Observable-Utility-Operators#subscribeon) to make it asynchronous, or by using a function that already makes asychronous calls. +Kick off your work for each item inside [`flatMap`](Transforming-Observables#flatmap-concatmap-and-flatmapiterable) using [`subscribeOn`](Observable-Utility-Operators#subscribeon) to make it asynchronous, or by using a function that already makes asynchronous calls. #### see also: * RxJava Threading Examples by Graham Lea @@ -136,7 +136,7 @@ Kick off your work for each item inside [`flatMap`](Transforming-Observables#fla ## parallelMerge( ) #### combine multiple Observables into a smaller number of Observables, to facilitate parallelism -​ +​ Use the `parallelMerge( )` method to take an Observable that emits a large number of Observables and to reduce it to an Observable that emits a particular, smaller number of Observables that emit the same set of items as the original larger set of Observables: for instance a number of Observables that matches the number of parallel processes that you want to use when processing the emissions from the complete set of Observables. @@ -144,7 +144,7 @@ Use the `parallelMerge( )` method to take an Observable that emits a large num ## pivot( ) #### combine multiple sets of grouped observables so that they are arranged primarily by group rather than by set -​ +​ If you combine multiple sets of grouped observables, such as those created by [`groupBy( )` and `groupByUntil( )`](Transforming-Observables#wiki-groupby-and-groupbyuntil), then even if those grouped observables have been grouped by a similar differentiation function, the resulting grouping will be primarily based on which set the observable came from, not on which group the observable belonged to. @@ -152,13 +152,13 @@ An example may make this clearer. Imagine you use `groupBy( )` to group the em The result will be a grouped observable that emits two groups: the grouped observable resulting from transforming Observable1, and the grouped observable resulting from transforming Observable2. Each of those grouped observables emit observables that in turn emit the odds and evens from the source observables. You can use `pivot( )` to change this around: by applying `pivot( )` to this grouped observable it will transform into one that emits two different groups: the odds group and the evens group, with each of these groups emitting a separate observable corresponding to which source observable its set of integers came from. Here is an illustration: -​ +​ *** ## publishLast( ) #### represent an Observable as a Connectable Observable that emits only the last item emitted by the source Observable - + #### see also: * RxJS: `publishLast` diff --git a/docs/What's-different-in-2.0.md b/docs/What's-different-in-2.0.md index fac50df56d2..edc681fa7fd 100644 --- a/docs/What's-different-in-2.0.md +++ b/docs/What's-different-in-2.0.md @@ -450,12 +450,12 @@ Before 2.0.7, the operator `strict()` had to be applied in order to achieve the As one of the primary goals of RxJava 2, the design focuses on performance and in order enable it, RxJava 2.0.7 adds a custom `io.reactivex.FlowableSubscriber` interface (extends `org.reactivestreams.Subscriber`) but adds no new methods to it. The new interface is **constrained to RxJava 2** and represents a consumer to `Flowable` that is able to work in a mode that relaxes the Reactive-Streams version 1.0.0 specification in rules §1.3, §2.3, §2.12 and §3.9: - - §1.3 relaxation: `onSubscribe` may run concurrently with `onNext` in case the `FlowableSubscriber` calls `request()` from inside `onSubscribe` and it is the resposibility of `FlowableSubscriber` to ensure thread-safety between the remaining instructions in `onSubscribe` and `onNext`. + - §1.3 relaxation: `onSubscribe` may run concurrently with `onNext` in case the `FlowableSubscriber` calls `request()` from inside `onSubscribe` and it is the responsibility of `FlowableSubscriber` to ensure thread-safety between the remaining instructions in `onSubscribe` and `onNext`. - §2.3 relaxation: calling `Subscription.cancel` and `Subscription.request` from `FlowableSubscriber.onComplete()` or `FlowableSubscriber.onError()` is considered a no-operation. - §2.12 relaxation: if the same `FlowableSubscriber` instance is subscribed to multiple sources, it must ensure its `onXXX` methods remain thread safe. - §3.9 relaxation: issuing a non-positive `request()` will not stop the current stream but signal an error via `RxJavaPlugins.onError`. -From a user's perspective, if one was using the the `subscribe` methods other than `Flowable.subscribe(Subscriber)`, there is no need to do anything regarding this change and there is no extra penalty for it. +From a user's perspective, if one was using the `subscribe` methods other than `Flowable.subscribe(Subscriber)`, there is no need to do anything regarding this change and there is no extra penalty for it. If one was using `Flowable.subscribe(Subscriber)` with the built-in RxJava `Subscriber` implementations such as `DisposableSubscriber`, `TestSubscriber` and `ResourceSubscriber`, there is a small runtime overhead (one `instanceof` check) associated when the code is not recompiled against 2.0.7. diff --git a/docs/Writing-operators-for-2.0.md b/docs/Writing-operators-for-2.0.md index e8486564b1f..1a51664880e 100644 --- a/docs/Writing-operators-for-2.0.md +++ b/docs/Writing-operators-for-2.0.md @@ -565,7 +565,7 @@ Version 2.0.7 introduced a new interface, `FlowableSubscriber` that extends `Sub The rule relaxations are as follows: -- §1.3 relaxation: `onSubscribe` may run concurrently with onNext in case the `FlowableSubscriber` calls `request()` from inside `onSubscribe` and it is the resposibility of `FlowableSubscriber` to ensure thread-safety between the remaining instructions in `onSubscribe` and `onNext`. +- §1.3 relaxation: `onSubscribe` may run concurrently with onNext in case the `FlowableSubscriber` calls `request()` from inside `onSubscribe` and it is the responsibility of `FlowableSubscriber` to ensure thread-safety between the remaining instructions in `onSubscribe` and `onNext`. - §2.3 relaxation: calling `Subscription.cancel` and `Subscription.request` from `FlowableSubscriber.onComplete()` or `FlowableSubscriber.onError()` is considered a no-operation. - §2.12 relaxation: if the same `FlowableSubscriber` instance is subscribed to multiple sources, it must ensure its `onXXX` methods remain thread safe. - §3.9 relaxation: issuing a non-positive `request()` will not stop the current stream but signal an error via `RxJavaPlugins.onError`. diff --git a/docs/_Sidebar.md b/docs/_Sidebar.md index 1fe03394079..22961acec3e 100644 --- a/docs/_Sidebar.md +++ b/docs/_Sidebar.md @@ -21,11 +21,12 @@ * [Transformation](https://github.com/ReactiveX/RxJava/wiki/Transforming-Observables) * [Utility](https://github.com/ReactiveX/RxJava/wiki/Observable-Utility-Operators) * [Notable 3rd party Operators (Alphabetical List)](https://github.com/ReactiveX/RxJava/wiki/Alphabetical-List-of-3rd-party-Operators) + * [Operator matrix](https://github.com/ReactiveX/RxJava/wiki/Operator-Matrix) * [Plugins](https://github.com/ReactiveX/RxJava/wiki/Plugins) * [How to Contribute](https://github.com/ReactiveX/RxJava/wiki/How-to-Contribute) * [Writing operators](https://github.com/ReactiveX/RxJava/wiki/Writing-operators-for-2.0) * [Backpressure](https://github.com/ReactiveX/RxJava/wiki/Backpressure-(2.0)) * [another explanation](https://github.com/ReactiveX/RxJava/wiki/Backpressure) -* [JavaDoc](http://reactivex.io/RxJava/2.x/javadoc) +* JavaDoc: [1.x](http://reactivex.io/RxJava/1.x/javadoc), [2.x](http://reactivex.io/RxJava/2.x/javadoc), [3.x](http://reactivex.io/RxJava/3.x/javadoc) * [Coming from RxJava 1](https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0) * [Additional Reading](https://github.com/ReactiveX/RxJava/wiki/Additional-Reading) diff --git a/docs/_Sidebar.md.md b/docs/_Sidebar.md.md index 1fe03394079..32e201fc464 100644 --- a/docs/_Sidebar.md.md +++ b/docs/_Sidebar.md.md @@ -21,6 +21,7 @@ * [Transformation](https://github.com/ReactiveX/RxJava/wiki/Transforming-Observables) * [Utility](https://github.com/ReactiveX/RxJava/wiki/Observable-Utility-Operators) * [Notable 3rd party Operators (Alphabetical List)](https://github.com/ReactiveX/RxJava/wiki/Alphabetical-List-of-3rd-party-Operators) + * [Operator matrix](https://github.com/ReactiveX/RxJava/wiki/Operator-Matrix) * [Plugins](https://github.com/ReactiveX/RxJava/wiki/Plugins) * [How to Contribute](https://github.com/ReactiveX/RxJava/wiki/How-to-Contribute) * [Writing operators](https://github.com/ReactiveX/RxJava/wiki/Writing-operators-for-2.0) diff --git a/gradle.properties b/gradle.properties index 820b2a5bc10..e685b8103a4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,24 @@ -release.scope=patch -release.version=3.0.0-SNAPSHOT +group=io.reactivex.rxjava3 +version=3.0.0-SNAPSHOT +description=RxJava: Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM. + +POM_ARTIFACT_ID=rxjava +POM_NAME=RxJava +POM_PACKAGING=jar + +POM_DESCRIPTION=Reactive Extensions for Java +POM_INCEPTION_YEAR=2013 + +POM_URL=https://github.com/ReactiveX/RxJava +POM_SCM_URL=https://github.com/ReactiveX/RxJava +POM_SCM_CONNECTION=scm:git:git://github.com/ReactiveX/RxJava.git +POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/ReactiveX/RxJava.git + +POM_LICENCE_NAME=The Apache Software License, Version 2.0 +POM_LICENCE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt +POM_LICENCE_DIST=repo + +POM_DEVELOPER_ID=akarnokd +POM_DEVELOPER_NAME=David Karnok +POM_DEVELOPER_URL=https://github.com/akarnokd/ +POM_DEVELOPER_EMAIL=akarnokd@gmail.com diff --git a/gradle/buildViaTravis.sh b/gradle/buildViaTravis.sh deleted file mode 100755 index ea385c3e920..00000000000 --- a/gradle/buildViaTravis.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# This script will build the project. - -buildTag="$TRAVIS_TAG" - -if [ "$buildTag" != "" ] && [ "${buildTag:0:3}" != "v3." ]; then - echo -e "Wrong tag on the 3.x brach: $buildTag : build stopped" - exit 1 -fi - -export GRADLE_OPTS=-Xmx1024m - -if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then - echo -e "Build Pull Request #$TRAVIS_PULL_REQUEST => Branch [$TRAVIS_BRANCH]" - ./gradlew -PreleaseMode=pr build --stacktrace -elif [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_TAG" == "" ]; then - if [ "$TRAVIS_BRANCH" != "3.x" ]; then - echo -e 'Build secondary Branch (no snapshot) => Branch ['$TRAVIS_BRANCH']' - ./gradlew -PreleaseMode=pr build --stacktrace - else - echo -e 'Build Branch with Snapshot => Branch ['$TRAVIS_BRANCH']' - ./gradlew -PreleaseMode=branch -PbintrayUser="${bintrayUser}" -PbintrayKey="${bintrayKey}" -PsonatypeUsername="${sonatypeUsername}" -PsonatypePassword="${sonatypePassword}" build --stacktrace - fi -elif [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_TAG" != "" ]; then - echo -e 'Build Branch for Release => Branch ['$TRAVIS_BRANCH'] Tag ['$TRAVIS_TAG']' - ./gradlew -PreleaseMode=full -PbintrayUser="${bintrayUser}" -PbintrayKey="${bintrayKey}" -PsonatypeUsername="${sonatypeUsername}" -PsonatypePassword="${sonatypePassword}" build --stacktrace -else - echo -e 'WARN: Should not be here => Branch ['$TRAVIS_BRANCH'] Tag ['$TRAVIS_TAG'] Pull Request ['$TRAVIS_PULL_REQUEST']' -fi diff --git a/gradle/javadoc_cleanup.gradle b/gradle/javadoc_cleanup.gradle index 12216464a7d..63b4f7f0456 100644 --- a/gradle/javadoc_cleanup.gradle +++ b/gradle/javadoc_cleanup.gradle @@ -1,36 +1,74 @@ // remove the excessive whitespaces between method arguments in the javadocs task javadocCleanup(dependsOn: "javadoc") doLast { - fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/core/Flowable.html')); - fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/core/Observable.html')); - fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/core/Single.html')); - fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/core/Maybe.html')); - fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/core/Completable.html')); + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/core/Flowable.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/core/Observable.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/core/Single.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/core/Maybe.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/core/Completable.html')) - fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/flowables/ConnectableFlowable.html')); - fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/observables/ConnectableObservable.html')); + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/flowables/ConnectableFlowable.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/observables/ConnectableObservable.html')) - fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/subjects/ReplaySubject.html')); - fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/processors/ReplayProcessor.html')); - fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/plugins/RxJavaPlugins.html')); + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/subjects/ReplaySubject.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/processors/ReplayProcessor.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/subjects/PublishSubject.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/processors/PublishProcessor.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/subjects/AsyncSubject.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/processors/AsyncProcessor.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/subjects/BehaviorSubject.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/processors/BehaviorProcessor.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/processors/MulticastProcessor.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/subjects/UnicastSubject.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/processors/UnicastProcessor.html')) - fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/parallel/ParallelFlowable.html')); + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/plugins/RxJavaPlugins.html')) + + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/parallel/ParallelFlowable.html')) + + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/disposables/Disposable.html')) + + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/observers/TestObserver.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/observers/BaseTestConsumer.html')) + fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/rxjava3/subscribers/TestSubscriber.html')) } def fixJavadocFile(file) { - println("Cleaning up: " + file); + logger.lifecycle("Cleaning up: " + file) String fileContents = file.getText('UTF-8') // lots of spaces after the previous method argument - fileContents = fileContents.replaceAll(",\\s{4,}", ",\n "); + fileContents = fileContents.replaceAll(",\\s{4,}", ",\n ") // lots of spaces after the @NonNull annotations - fileContents = fileContents.replaceAll("@NonNull\\s{4,}", "@NonNull "); + fileContents = fileContents.replaceAll("@NonNull\\s{4,}", "@NonNull ") // lots of spaces after the @Nullable annotations - fileContents = fileContents.replaceAll("@Nullable\\s{4,}", "@Nullable "); + fileContents = fileContents.replaceAll("@Nullable\\s{4,}", "@Nullable ") - file.setText(fileContents, 'UTF-8'); -} + // javadoc bug: duplicates the link to @NonNull for some reason + def nonNullText1 = "@NonNull" + + fileContents = fileContents.replace(nonNullText1 + " " + nonNullText1, nonNullText1) + fileContents = fileContents.replace(nonNullText1 + "\n " + nonNullText1, nonNullText1) + fileContents = fileContents.replace(nonNullText1 + "\r\n " + nonNullText1, nonNullText1) + + def nonNullText2 = "@NonNull" + fileContents = fileContents.replace(nonNullText2 + " " + nonNullText2, nonNullText2) + fileContents = fileContents.replace(nonNullText2 + "\n " + nonNullText2, nonNullText2) + fileContents = fileContents.replace(nonNullText2 + "\r\n " + nonNullText2, nonNullText2) -javadocJar.dependsOn javadocCleanup -build.dependsOn javadocCleanup \ No newline at end of file + // javadoc bug: duplicates the link to @Nullable for some reason + def nullableText1 = "@Nullable" + + fileContents = fileContents.replace(nullableText1 + " " + nullableText1, nullableText1) + fileContents = fileContents.replace(nullableText1 + "\n " + nullableText1, nullableText1) + fileContents = fileContents.replace(nullableText1 + "\r\n " + nullableText1, nullableText1) + + def nullableText2 = "@Nullable" + + fileContents = fileContents.replace(nullableText2 + " " + nullableText2, nullableText2) + fileContents = fileContents.replace(nullableText2 + "\n " + nullableText2, nullableText2) + fileContents = fileContents.replace(nullableText2 + "\r\n " + nullableText2, nullableText2) + + file.setText(fileContents, 'UTF-8') +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf016b..afba109285a 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 94920145f34..3c44eb1b6f5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 83f2acfdc31..65dcd68d65c 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,78 +17,113 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -105,84 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 9618d8d9607..93e3f59f135 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,10 +25,14 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,38 +65,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/gradle/push_javadoc.sh b/push_javadoc.sh similarity index 78% rename from gradle/push_javadoc.sh rename to push_javadoc.sh index c8f648258e0..28ce74f1db1 100644 --- a/gradle/push_javadoc.sh +++ b/push_javadoc.sh @@ -8,21 +8,9 @@ targetRepo=github.com/ReactiveX/RxJava.git # ======================================================================= -# only for main pushes, for now -if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then - echo -e "Pull request detected, skipping JavaDocs pushback." - exit 0 -fi - -# only when on the 3.x branch and not tagged -if [ "$TRAVIS_BRANCH" != "3.x" ] && [ "$TRAVIS_TAG" == "" ]; then - echo -e "On a secondary branch '$TRAVIS_BRANCH', skipping JavaDocs pushback." - exit 0 -fi - # get the current build tag if any -buildTag="$TRAVIS_TAG" -echo -e "Travis tag: '$buildTag'" +buildTag="$BUILD_TAG" +echo -e "Build tag: '$buildTag'" if [ "$buildTag" == "" ]; then buildTag="snapshot" @@ -33,18 +21,18 @@ fi echo -e "JavaDocs pushback for tag: $buildTag" # check if the token is actually there -if [ "$GITHUB_TOKEN" == "" ]; then +if [ "$JAVADOCS_TOKEN" == "" ]; then echo -e "No access to GitHub, skipping JavaDocs pushback." exit 0 fi # prepare the git information -git config --global user.email "travis@travis-ci.org" -git config --global user.name "Travis CI" +git config --global user.email "akarnokd+ci@gmail.com" +git config --global user.name "akarnokd+ci" # setup the remote echo -e "Adding the target repository to git" -git remote add origin-pages https://${GITHUB_TOKEN}@${targetRepo} > /dev/null 2>&1 +git remote add origin-pages https://${JAVADOCS_TOKEN}@${targetRepo} > /dev/null 2>&1 # stash changes due to chmod echo -e "Stashing any local non-ignored changes" @@ -119,8 +107,8 @@ echo -e "Removing deleted files" git add -u # commit all -echo -e "commit Travis build: $TRAVIS_BUILD_NUMBER for $buildTag" -git commit --message "Travis build: $TRAVIS_BUILD_NUMBER for $buildTag" +echo -e "commit CI build: $CI_BUILD_NUMBER for $buildTag" +git commit --message "CI build: $CI_BUILD_NUMBER for $buildTag" # debug file list #find -name "*.html" diff --git a/src/jmh/java/io/reactivex/rxjava3/core/BinaryFlatMapPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/BinaryFlatMapPerf.java index 836957192ec..6e6ae7e3c62 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/BinaryFlatMapPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/BinaryFlatMapPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -139,9 +139,9 @@ public Observable apply(Integer v) { } }); - singleFlatMapHideObservable = Single.just(1).flatMapObservable(new Function>() { + singleFlatMapHideObservable = Single.just(1).flatMapObservable(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return arrayObservableHide; } }); @@ -153,16 +153,16 @@ public Iterable apply(Integer v) { } }); - maybeFlatMapObservable = Maybe.just(1).flatMapObservable(new Function>() { + maybeFlatMapObservable = Maybe.just(1).flatMapObservable(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return arrayObservable; } }); - maybeFlatMapHideObservable = Maybe.just(1).flatMapObservable(new Function>() { + maybeFlatMapHideObservable = Maybe.just(1).flatMapObservable(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return arrayObservableHide; } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/core/BlockingGetPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/BlockingGetPerf.java index f40a8ca55b6..7f3711788ab 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/BlockingGetPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/BlockingGetPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/BlockingPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/BlockingPerf.java index 020befc21a1..5fb2825b3ee 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/BlockingPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/BlockingPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/CallableAsyncPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/CallableAsyncPerf.java index 8098b1aaf40..1bae28f9f9d 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/CallableAsyncPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/CallableAsyncPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/EachTypeFlatMapPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/EachTypeFlatMapPerf.java index 37a4f196e8f..14aa8c3605e 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/EachTypeFlatMapPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/EachTypeFlatMapPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/FlatMapJustPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/FlatMapJustPerf.java index 2a1fd7539c2..597fae480d6 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/FlatMapJustPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/FlatMapJustPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/FlattenCrossMapPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/FlattenCrossMapPerf.java index 866fe5de776..c5d516423f2 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/FlattenCrossMapPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/FlattenCrossMapPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/FlattenJustPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/FlattenJustPerf.java index d2ac9aa5b7c..3bb1ad1473e 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/FlattenJustPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/FlattenJustPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/FlattenRangePerf.java b/src/jmh/java/io/reactivex/rxjava3/core/FlattenRangePerf.java index a3195b760d4..0339f345c31 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/FlattenRangePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/FlattenRangePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/FlowableFlatMapCompletableAsyncPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/FlowableFlatMapCompletableAsyncPerf.java index e9494e97dff..0ebb2d4458b 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/FlowableFlatMapCompletableAsyncPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/FlowableFlatMapCompletableAsyncPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/FlowableFlatMapCompletableSyncPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/FlowableFlatMapCompletableSyncPerf.java index 34f53a954af..400e0609a8f 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/FlowableFlatMapCompletableSyncPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/FlowableFlatMapCompletableSyncPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/InputWithIncrementingInteger.java b/src/jmh/java/io/reactivex/rxjava3/core/InputWithIncrementingInteger.java index 772d202dca8..44d109fb4d5 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/InputWithIncrementingInteger.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/InputWithIncrementingInteger.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/JustAsyncPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/JustAsyncPerf.java index f60204c88b2..6906470aeaa 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/JustAsyncPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/JustAsyncPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/LatchedSingleObserver.java b/src/jmh/java/io/reactivex/rxjava3/core/LatchedSingleObserver.java index 1b908ac6b28..6bcdba465ed 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/LatchedSingleObserver.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/LatchedSingleObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/MemoryPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/MemoryPerf.java index c7c407de158..7cd45de74ee 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/MemoryPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/MemoryPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/ObservableFlatMapPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/ObservableFlatMapPerf.java index d0d75e78d4a..65145b07b42 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/ObservableFlatMapPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/ObservableFlatMapPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/OperatorFlatMapPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/OperatorFlatMapPerf.java index 0eb7f03aa9c..777fc9e1a6c 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/OperatorFlatMapPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/OperatorFlatMapPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/OperatorMergePerf.java b/src/jmh/java/io/reactivex/rxjava3/core/OperatorMergePerf.java index 560736c86c1..24605fc02a6 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/OperatorMergePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/OperatorMergePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/PerfAsyncConsumer.java b/src/jmh/java/io/reactivex/rxjava3/core/PerfAsyncConsumer.java index 7c222fddab0..ccaaf755735 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/PerfAsyncConsumer.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/PerfAsyncConsumer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/PerfBoundedSubscriber.java b/src/jmh/java/io/reactivex/rxjava3/core/PerfBoundedSubscriber.java index 8ec19a833ab..68083976be9 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/PerfBoundedSubscriber.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/PerfBoundedSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/PerfConsumer.java b/src/jmh/java/io/reactivex/rxjava3/core/PerfConsumer.java index 6025438218b..60f93f089a0 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/PerfConsumer.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/PerfConsumer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/PerfInteropConsumer.java b/src/jmh/java/io/reactivex/rxjava3/core/PerfInteropConsumer.java index 6dfbac7a310..fc7f0b04b0f 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/PerfInteropConsumer.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/PerfInteropConsumer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/PerfObserver.java b/src/jmh/java/io/reactivex/rxjava3/core/PerfObserver.java index 5f09b97ffe6..a62a1e68f60 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/PerfObserver.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/PerfObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/PerfSubscriber.java b/src/jmh/java/io/reactivex/rxjava3/core/PerfSubscriber.java index 51da5a5c53b..8c0f30cffa5 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/PerfSubscriber.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/PerfSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/PublishProcessorPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/PublishProcessorPerf.java index c64e1f794d0..1278bfd641c 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/PublishProcessorPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/PublishProcessorPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/RangePerf.java b/src/jmh/java/io/reactivex/rxjava3/core/RangePerf.java index c9723b086da..0773cd4f724 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/RangePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/RangePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/ReducePerf.java b/src/jmh/java/io/reactivex/rxjava3/core/ReducePerf.java index faf0423760c..3d2bb476c8a 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/ReducePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/ReducePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/RxVsStreamPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/RxVsStreamPerf.java index 74c8952c7a0..8861a6cdf53 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/RxVsStreamPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/RxVsStreamPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/StrictPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/StrictPerf.java index 59d17f4d60c..23315ef6179 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/StrictPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/StrictPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/TakeUntilPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/TakeUntilPerf.java index b2f89a39ca2..a6a39496059 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/TakeUntilPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/TakeUntilPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/ToFlowablePerf.java b/src/jmh/java/io/reactivex/rxjava3/core/ToFlowablePerf.java index 9c86e836784..7b7f0dc36d2 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/ToFlowablePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/ToFlowablePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/core/XMapYPerf.java b/src/jmh/java/io/reactivex/rxjava3/core/XMapYPerf.java index 6205efa25da..b95d76ffe46 100644 --- a/src/jmh/java/io/reactivex/rxjava3/core/XMapYPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/core/XMapYPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/parallel/ParallelPerf.java b/src/jmh/java/io/reactivex/rxjava3/parallel/ParallelPerf.java index 4eaac7b0dac..c6fd16ffb60 100644 --- a/src/jmh/java/io/reactivex/rxjava3/parallel/ParallelPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/parallel/ParallelPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -109,4 +109,4 @@ public void groupBy(Blackhole bh) { public void parallel(Blackhole bh) { subscribe(parallel, bh); } -} \ No newline at end of file +} diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapCompletablePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapCompletablePerf.java index 9e1096ab74a..f1124f7a81d 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapCompletablePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapCompletablePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapMaybeEmptyPerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapMaybeEmptyPerf.java index a211fbe8292..7eabfcfbded 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapMaybeEmptyPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapMaybeEmptyPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapMaybePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapMaybePerf.java index 059a0b162be..4310ea2e955 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapMaybePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapMaybePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -60,9 +60,9 @@ public Publisher apply(Integer v) { } }); - flowableDedicated = source.concatMapMaybe(new Function>() { + flowableDedicated = source.concatMapMaybe(new Function>() { @Override - public Maybe apply(Integer v) { + public Maybe apply(Integer v) { return Maybe.just(v); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapSinglePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapSinglePerf.java index e812708a156..cbeac5ada90 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapSinglePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableConcatMapSinglePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapCompletablePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapCompletablePerf.java index 1960735cfa4..b46725986fe 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapCompletablePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapCompletablePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapMaybeEmptyPerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapMaybeEmptyPerf.java index 96e6fcf6724..699f76c0743 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapMaybeEmptyPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapMaybeEmptyPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -60,9 +60,9 @@ public Publisher apply(Integer v) { } }); - flowableDedicated = source.flatMapMaybe(new Function>() { + flowableDedicated = source.flatMapMaybe(new Function>() { @Override - public Maybe apply(Integer v) { + public Maybe apply(Integer v) { return Maybe.empty(); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapMaybePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapMaybePerf.java index 2f71d5793e4..f81ed10ec33 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapMaybePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapMaybePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -60,9 +60,9 @@ public Publisher apply(Integer v) { } }); - flowableDedicated = source.flatMapMaybe(new Function>() { + flowableDedicated = source.flatMapMaybe(new Function>() { @Override - public Maybe apply(Integer v) { + public Maybe apply(Integer v) { return Maybe.just(v); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapSinglePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapSinglePerf.java index 2bbdf9bf958..5a92bf20ffb 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapSinglePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableFlatMapSinglePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -60,9 +60,9 @@ public Publisher apply(Integer v) { } }); - flowableDedicated = source.flatMapSingle(new Function>() { + flowableDedicated = source.flatMapSingle(new Function>() { @Override - public Single apply(Integer v) { + public Single apply(Integer v) { return Single.just(v); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapCompletablePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapCompletablePerf.java index 033d35c4290..4e419a5d2e7 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapCompletablePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapCompletablePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapMaybeEmptyPerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapMaybeEmptyPerf.java index adc60601893..46ce694f6dd 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapMaybeEmptyPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapMaybeEmptyPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -60,9 +60,9 @@ public Publisher apply(Integer v) { } }); - flowableDedicated = source.switchMapMaybe(new Function>() { + flowableDedicated = source.switchMapMaybe(new Function>() { @Override - public Maybe apply(Integer v) { + public Maybe apply(Integer v) { return Maybe.empty(); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapMaybePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapMaybePerf.java index d5d8cb9443e..e96bbc39194 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapMaybePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapMaybePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -60,9 +60,9 @@ public Publisher apply(Integer v) { } }); - flowableDedicated = source.switchMapMaybe(new Function>() { + flowableDedicated = source.switchMapMaybe(new Function>() { @Override - public Maybe apply(Integer v) { + public Maybe apply(Integer v) { return Maybe.just(v); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapSinglePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapSinglePerf.java index a997f27b537..ef06ebfa668 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapSinglePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/FlowableSwitchMapSinglePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -60,9 +60,9 @@ public Publisher apply(Integer v) { } }); - flowableDedicated = source.switchMapSingle(new Function>() { + flowableDedicated = source.switchMapSingle(new Function>() { @Override - public Single apply(Integer v) { + public Single apply(Integer v) { return Single.just(v); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapCompletablePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapCompletablePerf.java index ca6174a006e..2229eed77a9 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapCompletablePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapCompletablePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,16 +45,16 @@ public void setup() { Observable source = Observable.fromArray(sourceArray); - observablePlain = source.concatMap(new Function>() { + observablePlain = source.concatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Observable.empty(); } }); - observableConvert = source.concatMap(new Function>() { + observableConvert = source.concatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Completable.complete().toObservable(); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapMaybeEmptyPerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapMaybeEmptyPerf.java index b194580fa8f..cfde5183e5f 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapMaybeEmptyPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapMaybeEmptyPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,23 +45,23 @@ public void setup() { Observable source = Observable.fromArray(sourceArray); - observablePlain = source.concatMap(new Function>() { + observablePlain = source.concatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Observable.empty(); } }); - concatMapToObservableEmpty = source.concatMap(new Function>() { + concatMapToObservableEmpty = source.concatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Maybe.empty().toObservable(); } }); - observableDedicated = source.concatMapMaybe(new Function>() { + observableDedicated = source.concatMapMaybe(new Function>() { @Override - public Maybe apply(Integer v) { + public Maybe apply(Integer v) { return Maybe.empty(); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapMaybePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapMaybePerf.java index 5c7d6ad7a09..75e75067245 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapMaybePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapMaybePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,23 +45,23 @@ public void setup() { Observable source = Observable.fromArray(sourceArray); - observablePlain = source.concatMap(new Function>() { + observablePlain = source.concatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Observable.just(v); } }); - observableConvert = source.concatMap(new Function>() { + observableConvert = source.concatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Maybe.just(v).toObservable(); } }); - observableDedicated = source.concatMapMaybe(new Function>() { + observableDedicated = source.concatMapMaybe(new Function>() { @Override - public Maybe apply(Integer v) { + public Maybe apply(Integer v) { return Maybe.just(v); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapSinglePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapSinglePerf.java index 1785b591355..4227791222b 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapSinglePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableConcatMapSinglePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,23 +45,23 @@ public void setup() { Observable source = Observable.fromArray(sourceArray); - observablePlain = source.concatMap(new Function>() { + observablePlain = source.concatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Observable.just(v); } }); - observableConvert = source.concatMap(new Function>() { + observableConvert = source.concatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Single.just(v).toObservable(); } }); - observableDedicated = source.concatMapSingle(new Function>() { + observableDedicated = source.concatMapSingle(new Function>() { @Override - public Single apply(Integer v) { + public Single apply(Integer v) { return Single.just(v); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapCompletablePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapCompletablePerf.java index 64247ac219a..6a916a68f1e 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapCompletablePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapCompletablePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,16 +45,16 @@ public void setup() { Observable source = Observable.fromArray(sourceArray); - observablePlain = source.flatMap(new Function>() { + observablePlain = source.flatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Observable.empty(); } }); - observableConvert = source.flatMap(new Function>() { + observableConvert = source.flatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Completable.complete().toObservable(); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapMaybeEmptyPerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapMaybeEmptyPerf.java index 5e38b30061c..377a8bba933 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapMaybeEmptyPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapMaybeEmptyPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,23 +45,23 @@ public void setup() { Observable source = Observable.fromArray(sourceArray); - observablePlain = source.flatMap(new Function>() { + observablePlain = source.flatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Observable.empty(); } }); - observableConvert = source.flatMap(new Function>() { + observableConvert = source.flatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Maybe.empty().toObservable(); } }); - observableDedicated = source.flatMapMaybe(new Function>() { + observableDedicated = source.flatMapMaybe(new Function>() { @Override - public Maybe apply(Integer v) { + public Maybe apply(Integer v) { return Maybe.empty(); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapMaybePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapMaybePerf.java index ffc5b15e564..248ca981126 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapMaybePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapMaybePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,23 +45,23 @@ public void setup() { Observable source = Observable.fromArray(sourceArray); - observablePlain = source.flatMap(new Function>() { + observablePlain = source.flatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Observable.just(v); } }); - observableConvert = source.flatMap(new Function>() { + observableConvert = source.flatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Maybe.just(v).toObservable(); } }); - observableDedicated = source.flatMapMaybe(new Function>() { + observableDedicated = source.flatMapMaybe(new Function>() { @Override - public Maybe apply(Integer v) { + public Maybe apply(Integer v) { return Maybe.just(v); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapSinglePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapSinglePerf.java index 6356ad8acee..880da95f5a1 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapSinglePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableFlatMapSinglePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,23 +45,23 @@ public void setup() { Observable source = Observable.fromArray(sourceArray); - observablePlain = source.flatMap(new Function>() { + observablePlain = source.flatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Observable.just(v); } }); - observableConvert = source.flatMap(new Function>() { + observableConvert = source.flatMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Single.just(v).toObservable(); } }); - observableDedicated = source.flatMapSingle(new Function>() { + observableDedicated = source.flatMapSingle(new Function>() { @Override - public Single apply(Integer v) { + public Single apply(Integer v) { return Single.just(v); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapCompletablePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapCompletablePerf.java index 1fc6eef9b39..41964c3dbde 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapCompletablePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapCompletablePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,16 +45,16 @@ public void setup() { Observable source = Observable.fromArray(sourceArray); - observablePlain = source.switchMap(new Function>() { + observablePlain = source.switchMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Observable.empty(); } }); - observableConvert = source.switchMap(new Function>() { + observableConvert = source.switchMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Completable.complete().toObservable(); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapMaybeEmptyPerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapMaybeEmptyPerf.java index 47374934206..6a4ea5c73bd 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapMaybeEmptyPerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapMaybeEmptyPerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,23 +45,23 @@ public void setup() { Observable source = Observable.fromArray(sourceArray); - observablePlain = source.switchMap(new Function>() { + observablePlain = source.switchMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Observable.empty(); } }); - observableConvert = source.switchMap(new Function>() { + observableConvert = source.switchMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Maybe.empty().toObservable(); } }); - observableDedicated = source.switchMapMaybe(new Function>() { + observableDedicated = source.switchMapMaybe(new Function>() { @Override - public Maybe apply(Integer v) { + public Maybe apply(Integer v) { return Maybe.empty(); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapMaybePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapMaybePerf.java index b8dca2d95ba..f0c32858904 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapMaybePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapMaybePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,23 +45,23 @@ public void setup() { Observable source = Observable.fromArray(sourceArray); - observablePlain = source.switchMap(new Function>() { + observablePlain = source.switchMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Observable.just(v); } }); - observableConvert = source.switchMap(new Function>() { + observableConvert = source.switchMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Maybe.just(v).toObservable(); } }); - observableDedicated = source.switchMapMaybe(new Function>() { + observableDedicated = source.switchMapMaybe(new Function>() { @Override - public Maybe apply(Integer v) { + public Maybe apply(Integer v) { return Maybe.just(v); } }); diff --git a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapSinglePerf.java b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapSinglePerf.java index 682e2712f00..087f32c8e36 100644 --- a/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapSinglePerf.java +++ b/src/jmh/java/io/reactivex/rxjava3/xmapz/ObservableSwitchMapSinglePerf.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,23 +45,23 @@ public void setup() { Observable source = Observable.fromArray(sourceArray); - observablePlain = source.switchMap(new Function>() { + observablePlain = source.switchMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Observable.just(v); } }); - observableConvert = source.switchMap(new Function>() { + observableConvert = source.switchMap(new Function>() { @Override - public Observable apply(Integer v) { + public Observable apply(Integer v) { return Single.just(v).toObservable(); } }); - observableDedicated = source.switchMapSingle(new Function>() { + observableDedicated = source.switchMapSingle(new Function>() { @Override - public Single apply(Integer v) { + public Single apply(Integer v) { return Single.just(v); } }); diff --git a/src/main/java/io/reactivex/rxjava3/annotations/BackpressureKind.java b/src/main/java/io/reactivex/rxjava3/annotations/BackpressureKind.java index fd53c196b34..3b979a045da 100644 --- a/src/main/java/io/reactivex/rxjava3/annotations/BackpressureKind.java +++ b/src/main/java/io/reactivex/rxjava3/annotations/BackpressureKind.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/annotations/BackpressureSupport.java b/src/main/java/io/reactivex/rxjava3/annotations/BackpressureSupport.java index 9deafa22f5f..b73a477fec1 100644 --- a/src/main/java/io/reactivex/rxjava3/annotations/BackpressureSupport.java +++ b/src/main/java/io/reactivex/rxjava3/annotations/BackpressureSupport.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/annotations/Beta.java b/src/main/java/io/reactivex/rxjava3/annotations/Beta.java index 123842b7739..ca75ea0b3b1 100644 --- a/src/main/java/io/reactivex/rxjava3/annotations/Beta.java +++ b/src/main/java/io/reactivex/rxjava3/annotations/Beta.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/annotations/CheckReturnValue.java b/src/main/java/io/reactivex/rxjava3/annotations/CheckReturnValue.java index 3091d2647fd..02c7f2e0d92 100644 --- a/src/main/java/io/reactivex/rxjava3/annotations/CheckReturnValue.java +++ b/src/main/java/io/reactivex/rxjava3/annotations/CheckReturnValue.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/annotations/Experimental.java b/src/main/java/io/reactivex/rxjava3/annotations/Experimental.java index 32d60e14424..061361f9b4d 100644 --- a/src/main/java/io/reactivex/rxjava3/annotations/Experimental.java +++ b/src/main/java/io/reactivex/rxjava3/annotations/Experimental.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/annotations/NonNull.java b/src/main/java/io/reactivex/rxjava3/annotations/NonNull.java index 03e51805888..4495092fc7c 100644 --- a/src/main/java/io/reactivex/rxjava3/annotations/NonNull.java +++ b/src/main/java/io/reactivex/rxjava3/annotations/NonNull.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/annotations/Nullable.java b/src/main/java/io/reactivex/rxjava3/annotations/Nullable.java index c95ef4a35c3..a6af9eb1b59 100644 --- a/src/main/java/io/reactivex/rxjava3/annotations/Nullable.java +++ b/src/main/java/io/reactivex/rxjava3/annotations/Nullable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/annotations/SchedulerSupport.java b/src/main/java/io/reactivex/rxjava3/annotations/SchedulerSupport.java index 53b395f06b1..0132b6a33d3 100644 --- a/src/main/java/io/reactivex/rxjava3/annotations/SchedulerSupport.java +++ b/src/main/java/io/reactivex/rxjava3/annotations/SchedulerSupport.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/annotations/package-info.java b/src/main/java/io/reactivex/rxjava3/annotations/package-info.java index 8fa44fd5535..a4daca2a325 100644 --- a/src/main/java/io/reactivex/rxjava3/annotations/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/annotations/package-info.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ /** diff --git a/src/main/java/io/reactivex/rxjava3/core/BackpressureOverflowStrategy.java b/src/main/java/io/reactivex/rxjava3/core/BackpressureOverflowStrategy.java index 750a1308f21..144dbb68076 100644 --- a/src/main/java/io/reactivex/rxjava3/core/BackpressureOverflowStrategy.java +++ b/src/main/java/io/reactivex/rxjava3/core/BackpressureOverflowStrategy.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.core; /** diff --git a/src/main/java/io/reactivex/rxjava3/core/BackpressureStrategy.java b/src/main/java/io/reactivex/rxjava3/core/BackpressureStrategy.java index 4a260726508..f2bf8d01ae4 100644 --- a/src/main/java/io/reactivex/rxjava3/core/BackpressureStrategy.java +++ b/src/main/java/io/reactivex/rxjava3/core/BackpressureStrategy.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/core/Completable.java b/src/main/java/io/reactivex/rxjava3/core/Completable.java index 1f24e413f5a..e31a44c32c3 100644 --- a/src/main/java/io/reactivex/rxjava3/core/Completable.java +++ b/src/main/java/io/reactivex/rxjava3/core/Completable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.core; import java.util.*; @@ -18,7 +19,7 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.annotations.*; -import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.*; @@ -51,7 +52,7 @@ * Note that as with the {@code Observable} protocol, {@code onError} and {@code onComplete} are mutually exclusive events. *

* Like {@code Observable}, a running {@code Completable} can be stopped through the {@link Disposable} instance - * provided to consumers through {@link SingleObserver#onSubscribe}. + * provided to consumers through {@link CompletableObserver#onSubscribe}. *

* Like an {@code Observable}, a {@code Completable} is lazy, can be either "hot" or "cold", synchronous or * asynchronous. {@code Completable} instances returned by the methods of this class are cold @@ -151,7 +152,7 @@ public static Completable ambArray(@NonNull CompletableSource... sources) { @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Completable amb(@NonNull Iterable sources) { + public static Completable amb(@NonNull Iterable<@NonNull ? extends CompletableSource> sources) { Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new CompletableAmb(null, sources)); @@ -165,7 +166,7 @@ public static Completable amb(@NonNull Iterable sou *

Scheduler:
*
{@code complete} does not operate by default on a particular {@link Scheduler}.
* - * @return a {@code Completable} instance that completes immediately + * @return the shared {@code Completable} instance */ @CheckReturnValue @NonNull @@ -177,13 +178,13 @@ public static Completable complete() { /** * Returns a {@code Completable} which completes only when all sources complete, one after another. *

- * + * *

*
Scheduler:
*
{@code concatArray} does not operate by default on a particular {@link Scheduler}.
*
* @param sources the sources to concatenate - * @return the {@code Completable} instance which completes only when all sources complete + * @return the new {@code Completable} instance * @throws NullPointerException if {@code sources} is {@code null} */ @CheckReturnValue @@ -201,6 +202,27 @@ public static Completable concatArray(@NonNull CompletableSource... sources) { return RxJavaPlugins.onAssembly(new CompletableConcatArray(sources)); } + /** + * Returns a {@code Completable} which completes only when all sources complete, one after another. + *

+ * + *

+ *
Scheduler:
+ *
{@code concatArrayDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param sources the sources to concatenate + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @SafeVarargs + public static Completable concatArrayDelayError(@NonNull CompletableSource... sources) { + return Flowable.fromArray(sources).concatMapCompletableDelayError(Functions.identity(), true, 2); + } + /** * Returns a {@code Completable} which completes only when all sources complete, one after another. *

@@ -210,13 +232,13 @@ public static Completable concatArray(@NonNull CompletableSource... sources) { *

{@code concat} does not operate by default on a particular {@link Scheduler}.
* * @param sources the sources to concatenate - * @return the {@code Completable} instance which completes only when all sources complete + * @return the new {@code Completable} instance * @throws NullPointerException if {@code sources} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Completable concat(@NonNull Iterable sources) { + public static Completable concat(@NonNull Iterable<@NonNull ? extends CompletableSource> sources) { Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new CompletableConcatIterable(sources)); @@ -225,7 +247,7 @@ public static Completable concat(@NonNull Iterable /** * Returns a {@code Completable} which completes only when all sources complete, one after another. *

- * + * *

*
Backpressure:
*
The returned {@code Completable} honors the backpressure of the downstream consumer @@ -234,21 +256,21 @@ public static Completable concat(@NonNull Iterable *
{@code concat} does not operate by default on a particular {@link Scheduler}.
*
* @param sources the sources to concatenate - * @return the {@code Completable} instance which completes only when all sources complete - * @throws NullPointerException if sources is {@code null} + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code sources} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.FULL) @NonNull - public static Completable concat(@NonNull Publisher sources) { + public static Completable concat(@NonNull Publisher<@NonNull ? extends CompletableSource> sources) { return concat(sources, 2); } /** * Returns a {@code Completable} which completes only when all sources complete, one after another. *

- * + * *

*
Backpressure:
*
The returned {@code Completable} honors the backpressure of the downstream consumer @@ -258,7 +280,7 @@ public static Completable concat(@NonNull Publisher *
* @param sources the sources to concatenate * @param prefetch the number of sources to prefetch from the sources - * @return the {@code Completable} instance which completes only when all sources complete + * @return the new {@code Completable} instance * @throws NullPointerException if {@code sources} is {@code null} * @throws IllegalArgumentException if {@code prefetch} is non-positive */ @@ -266,12 +288,82 @@ public static Completable concat(@NonNull Publisher @NonNull @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.FULL) - public static Completable concat(@NonNull Publisher sources, int prefetch) { + public static Completable concat(@NonNull Publisher<@NonNull ? extends CompletableSource> sources, int prefetch) { Objects.requireNonNull(sources, "sources is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); return RxJavaPlugins.onAssembly(new CompletableConcat(sources, prefetch)); } + /** + * Returns a {@code Completable} which completes only when all sources complete, one after another. + *

+ * + *

+ *
Scheduler:
+ *
{@code concatDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param sources the sources to concatenate + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static Completable concatDelayError(@NonNull Iterable<@NonNull ? extends CompletableSource> sources) { + return Flowable.fromIterable(sources).concatMapCompletableDelayError(Functions.identity()); + } + + /** + * Returns a {@code Completable} which completes only when all sources complete, one after another. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Completable} honors the backpressure of the downstream consumer + * and expects the other {@link Publisher} to honor it as well.
+ *
Scheduler:
+ *
{@code concatDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param sources the sources to concatenate + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.FULL) + @NonNull + public static Completable concatDelayError(@NonNull Publisher<@NonNull ? extends CompletableSource> sources) { + return concatDelayError(sources, 2); + } + + /** + * Returns a {@code Completable} which completes only when all sources complete, one after another. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Completable} honors the backpressure of the downstream consumer + * and expects the other {@link Publisher} to honor it as well.
+ *
Scheduler:
+ *
{@code concatDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param sources the sources to concatenate + * @param prefetch the number of sources to prefetch from the sources + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.FULL) + public static Completable concatDelayError(@NonNull Publisher<@NonNull ? extends CompletableSource> sources, int prefetch) { + return Flowable.fromPublisher(sources).concatMapCompletableDelayError(Functions.identity(), true, prefetch); + } + /** * Provides an API (via a cold {@code Completable}) that bridges the reactive world with the callback-style world. *

@@ -322,6 +414,29 @@ public static Completable create(@NonNull CompletableOnSubscribe source) { return RxJavaPlugins.onAssembly(new CompletableCreate(source)); } + /** + * Compares two {@link CompletableSource}s and emits {@code true} via a {@link Single} if both complete. + *

+ * + *

+ *
Scheduler:
+ *
{@code sequenceEqual} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param source1 the first {@code CompletableSource} instance + * @param source2 the second {@code CompletableSource} instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static Single sequenceEqual(@NonNull CompletableSource source1, @NonNull CompletableSource source2) { // NOPMD + Objects.requireNonNull(source1, "source1 is null"); + Objects.requireNonNull(source2, "source2 is null"); + return mergeArrayDelayError(source1, source2).andThen(Single.just(true)); + } + /** * Constructs a {@code Completable} instance by wrapping the given source callback * without any safeguards; you should manage the lifecycle and response @@ -332,20 +447,21 @@ public static Completable create(@NonNull CompletableOnSubscribe source) { *
Scheduler:
*
{@code unsafeCreate} does not operate by default on a particular {@link Scheduler}.
* - * @param source the callback which will receive the {@link CompletableObserver} instances + * @param onSubscribe the callback which will receive the {@link CompletableObserver} instances * when the {@code Completable} is subscribed to. - * @return the created {@code Completable} instance - * @throws NullPointerException if {@code source} is {@code null} + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code onSubscribe} is {@code null} + * @throws IllegalArgumentException if {@code source} is a {@code Completable} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Completable unsafeCreate(@NonNull CompletableSource source) { - Objects.requireNonNull(source, "source is null"); - if (source instanceof Completable) { + public static Completable unsafeCreate(@NonNull CompletableSource onSubscribe) { + Objects.requireNonNull(onSubscribe, "onSubscribe is null"); + if (onSubscribe instanceof Completable) { throw new IllegalArgumentException("Use of unsafeCreate(Completable)!"); } - return RxJavaPlugins.onAssembly(new CompletableFromUnsafeSource(source)); + return RxJavaPlugins.onAssembly(new CompletableFromUnsafeSource(onSubscribe)); } /** @@ -356,16 +472,16 @@ public static Completable unsafeCreate(@NonNull CompletableSource source) { *
Scheduler:
*
{@code defer} does not operate by default on a particular {@link Scheduler}.
* - * @param completableSupplier the supplier that returns the {@code Completable} that will be subscribed to. - * @return the {@code Completable} instance - * @throws NullPointerException if {@code completableSupplier} is {@code null} + * @param supplier the supplier that returns the {@code Completable} that will be subscribed to. + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code supplier} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Completable defer(@NonNull Supplier completableSupplier) { - Objects.requireNonNull(completableSupplier, "completableSupplier"); - return RxJavaPlugins.onAssembly(new CompletableDefer(completableSupplier)); + public static Completable defer(@NonNull Supplier supplier) { + Objects.requireNonNull(supplier, "supplier is null"); + return RxJavaPlugins.onAssembly(new CompletableDefer(supplier)); } /** @@ -380,16 +496,16 @@ public static Completable defer(@NonNull Supplier c *
Scheduler:
*
{@code error} does not operate by default on a particular {@link Scheduler}.
* - * @param errorSupplier the error supplier, not {@code null} + * @param supplier the error supplier, not {@code null} * @return the new {@code Completable} instance - * @throws NullPointerException if {@code errorSupplier} is {@code null} + * @throws NullPointerException if {@code supplier} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Completable error(@NonNull Supplier errorSupplier) { - Objects.requireNonNull(errorSupplier, "errorSupplier is null"); - return RxJavaPlugins.onAssembly(new CompletableErrorSupplier(errorSupplier)); + public static Completable error(@NonNull Supplier supplier) { + Objects.requireNonNull(supplier, "supplier is null"); + return RxJavaPlugins.onAssembly(new CompletableErrorSupplier(supplier)); } /** @@ -400,21 +516,21 @@ public static Completable error(@NonNull Supplier errorSupp *
Scheduler:
*
{@code error} does not operate by default on a particular {@link Scheduler}.
* - * @param error the {@code Throwable} instance to emit, not {@code null} + * @param throwable the {@code Throwable} instance to emit, not {@code null} * @return the new {@code Completable} instance - * @throws NullPointerException if {@code error} is {@code null} + * @throws NullPointerException if {@code throwable} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Completable error(@NonNull Throwable error) { - Objects.requireNonNull(error, "error is null"); - return RxJavaPlugins.onAssembly(new CompletableError(error)); + public static Completable error(@NonNull Throwable throwable) { + Objects.requireNonNull(throwable, "throwable is null"); + return RxJavaPlugins.onAssembly(new CompletableError(throwable)); } /** - * Returns a {@code Completable} instance that runs the given {@link Action} for each subscriber and - * emits either an unchecked exception or simply completes. + * Returns a {@code Completable} instance that runs the given {@link Action} for each {@link CompletableObserver} and + * emits either an exception or simply completes. *

* *

@@ -428,16 +544,16 @@ public static Completable error(@NonNull Throwable error) { * {@link RxJavaPlugins#onError(Throwable)} as an {@link io.reactivex.rxjava3.exceptions.UndeliverableException UndeliverableException}. * *
- * @param run the {@code Action} to run for each subscribing {@link CompletableObserver} + * @param action the {@code Action} to run for each subscribing {@code CompletableObserver} * @return the new {@code Completable} instance - * @throws NullPointerException if {@code run} is {@code null} + * @throws NullPointerException if {@code action} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Completable fromAction(@NonNull Action run) { - Objects.requireNonNull(run, "run is null"); - return RxJavaPlugins.onAssembly(new CompletableFromAction(run)); + public static Completable fromAction(@NonNull Action action) { + Objects.requireNonNull(action, "action is null"); + return RxJavaPlugins.onAssembly(new CompletableFromAction(action)); } /** @@ -485,6 +601,7 @@ public static Completable fromCallable(@NonNull Callable callable) { * @param future the {@code Future} to react to * @return the new {@code Completable} instance * @throws NullPointerException if {@code future} is {@code null} + * @see #fromCompletionStage(CompletionStage) */ @CheckReturnValue @NonNull @@ -495,7 +612,7 @@ public static Completable fromFuture(@NonNull Future future) { } /** - * Returns a {@code Completable} instance that when subscribed to, subscribes to the {@link Maybe} instance and + * Returns a {@code Completable} instance that when subscribed to, subscribes to the {@link MaybeSource} instance and * emits an {@code onComplete} event if the maybe emits {@code onSuccess}/{@code onComplete} or forwards any * {@code onError} events. *

@@ -505,8 +622,8 @@ public static Completable fromFuture(@NonNull Future future) { *

{@code fromMaybe} does not operate by default on a particular {@link Scheduler}.
* *

History: 2.1.17 - beta - * @param the value type of the {@link MaybeSource} element - * @param maybe the {@code Maybe} instance to subscribe to, not {@code null} + * @param the value type of the {@code MaybeSource} element + * @param maybe the {@code MaybeSource} instance to subscribe to, not {@code null} * @return the new {@code Completable} instance * @throws NullPointerException if {@code maybe} is {@code null} * @since 2.2 @@ -514,21 +631,26 @@ public static Completable fromFuture(@NonNull Future future) { @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Completable fromMaybe(@NonNull MaybeSource maybe) { + public static <@NonNull T> Completable fromMaybe(@NonNull MaybeSource maybe) { Objects.requireNonNull(maybe, "maybe is null"); return RxJavaPlugins.onAssembly(new MaybeIgnoreElementCompletable<>(maybe)); } /** * Returns a {@code Completable} instance that runs the given {@link Runnable} for each {@link CompletableObserver} and - * emits either its exception or simply completes. + * emits either its unchecked exception or simply completes. *

* + *

+ * If the code to be wrapped needs to throw a checked or more broader {@link Throwable} exception, that + * exception has to be converted to an unchecked exception by the wrapped code itself. Alternatively, + * use the {@link #fromAction(Action)} method which allows the wrapped code to throw any {@code Throwable} + * exception and will signal it to observers as-is. *

*
Scheduler:
*
{@code fromRunnable} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If the {@code Runnable} throws an exception, the respective {@link Throwable} is + *
If the {@code Runnable} throws an exception, the respective {@code Throwable} is * delivered to the downstream via {@link CompletableObserver#onError(Throwable)}, * except when the downstream has disposed this {@code Completable} source. * In this latter case, the {@code Throwable} is delivered to the global error handler via @@ -538,6 +660,7 @@ public static Completable fromMaybe(@NonNull MaybeSource maybe) { * @param run the {@code Runnable} to run for each {@code CompletableObserver} * @return the new {@code Completable} instance * @throws NullPointerException if {@code run} is {@code null} + * @see #fromAction(Action) */ @CheckReturnValue @NonNull @@ -564,7 +687,7 @@ public static Completable fromRunnable(@NonNull Runnable run) { @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Completable fromObservable(@NonNull ObservableSource observable) { + public static <@NonNull T> Completable fromObservable(@NonNull ObservableSource observable) { Objects.requireNonNull(observable, "observable is null"); return RxJavaPlugins.onAssembly(new CompletableFromObservable<>(observable)); } @@ -602,7 +725,7 @@ public static Completable fromObservable(@NonNull ObservableSource observ @NonNull @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) - public static Completable fromPublisher(@NonNull Publisher publisher) { + public static <@NonNull T> Completable fromPublisher(@NonNull Publisher publisher) { Objects.requireNonNull(publisher, "publisher is null"); return RxJavaPlugins.onAssembly(new CompletableFromPublisher<>(publisher)); } @@ -624,7 +747,7 @@ public static Completable fromPublisher(@NonNull Publisher publisher) { @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Completable fromSingle(@NonNull SingleSource single) { + public static <@NonNull T> Completable fromSingle(@NonNull SingleSource single) { Objects.requireNonNull(single, "single is null"); return RxJavaPlugins.onAssembly(new CompletableFromSingle<>(single)); } @@ -732,7 +855,7 @@ public static Completable mergeArray(@NonNull CompletableSource... sources) { @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Completable merge(@NonNull Iterable sources) { + public static Completable merge(@NonNull Iterable<@NonNull ? extends CompletableSource> sources) { Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new CompletableMergeIterable(sources)); } @@ -771,7 +894,7 @@ public static Completable merge(@NonNull Iterable s @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @NonNull - public static Completable merge(@NonNull Publisher sources) { + public static Completable merge(@NonNull Publisher<@NonNull ? extends CompletableSource> sources) { return merge0(sources, Integer.MAX_VALUE, false); } @@ -812,7 +935,7 @@ public static Completable merge(@NonNull Publisher @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.FULL) @NonNull - public static Completable merge(@NonNull Publisher sources, int maxConcurrency) { + public static Completable merge(@NonNull Publisher<@NonNull ? extends CompletableSource> sources, int maxConcurrency) { return merge0(sources, maxConcurrency, false); } @@ -839,7 +962,7 @@ public static Completable merge(@NonNull Publisher @NonNull @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.FULL) - private static Completable merge0(@NonNull Publisher sources, int maxConcurrency, boolean delayErrors) { + private static Completable merge0(@NonNull Publisher<@NonNull ? extends CompletableSource> sources, int maxConcurrency, boolean delayErrors) { Objects.requireNonNull(sources, "sources is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); return RxJavaPlugins.onAssembly(new CompletableMerge(sources, maxConcurrency, delayErrors)); @@ -865,7 +988,7 @@ private static Completable merge0(@NonNull Publisher - * + * *
*
Scheduler:
*
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -885,7 +1008,7 @@ public static Completable mergeArrayDelayError(@NonNull CompletableSource... sou @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Completable mergeDelayError(@NonNull Iterable sources) { + public static Completable mergeDelayError(@NonNull Iterable<@NonNull ? extends CompletableSource> sources) { Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new CompletableMergeDelayErrorIterable(sources)); } @@ -911,7 +1034,7 @@ public static Completable mergeDelayError(@NonNull Iterable sources) { + public static Completable mergeDelayError(@NonNull Publisher<@NonNull ? extends CompletableSource> sources) { return merge0(sources, Integer.MAX_VALUE, true); } @@ -934,12 +1057,13 @@ public static Completable mergeDelayError(@NonNull Publisher sources, int maxConcurrency) { + public static Completable mergeDelayError(@NonNull Publisher<@NonNull ? extends CompletableSource> sources, int maxConcurrency) { return merge0(sources, maxConcurrency, true); } @@ -1007,7 +1131,7 @@ public static Completable timer(long delay, @NonNull TimeUnit unit, @NonNull Sch /** * Creates a {@link NullPointerException} instance and sets the given {@link Throwable} as its initial cause. * @param ex the {@code Throwable} instance to use as cause, not {@code null} (not verified) - * @return the created {@code NullPointerException} + * @return the new {@code NullPointerException} */ private static NullPointerException toNpe(Throwable ex) { NullPointerException npe = new NullPointerException("Actually not, but can't pass out an exception otherwise..."); @@ -1015,11 +1139,76 @@ private static NullPointerException toNpe(Throwable ex) { return npe; } + /** + * Switches between {@link CompletableSource}s emitted by the source {@link Publisher} whenever + * a new {@code CompletableSource} is emitted, disposing the previously running {@code CompletableSource}, + * exposing the setup as a {@code Completable} sequence. + *

+ * + *

+ *
Backpressure:
+ *
The {@code sources} {@code Publisher} is consumed in an unbounded manner (requesting {@link Long#MAX_VALUE}).
+ *
Scheduler:
+ *
{@code switchOnNext} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
The returned sequence fails with the first error signaled by the {@code sources} {@code Publisher} + * or the currently running {@code CompletableSource}, disposing the rest. Late errors are + * forwarded to the global error handler via {@link RxJavaPlugins#onError(Throwable)}.
+ *
+ * @param sources the {@code Publisher} sequence of inner {@code CompletableSource}s to switch between + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + * @see #switchOnNextDelayError(Publisher) + * @see ReactiveX operators documentation: Switch + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) + public static Completable switchOnNext(@NonNull Publisher<@NonNull ? extends CompletableSource> sources) { + Objects.requireNonNull(sources, "sources is null"); + return RxJavaPlugins.onAssembly(new FlowableSwitchMapCompletablePublisher<>(sources, Functions.identity(), false)); + } + + /** + * Switches between {@link CompletableSource}s emitted by the source {@link Publisher} whenever + * a new {@code CompletableSource} is emitted, disposing the previously running {@code CompletableSource}, + * exposing the setup as a {@code Completable} sequence and delaying all errors from + * all of them until all terminate. + *

+ * + *

+ *
Backpressure:
+ *
The {@code sources} {@code Publisher} is consumed in an unbounded manner (requesting {@link Long#MAX_VALUE}).
+ *
Scheduler:
+ *
{@code switchOnNextDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
The returned {@code Completable} collects all errors emitted by either the {@code sources} + * {@code Publisher} or any inner {@code CompletableSource} and emits them as a {@link CompositeException} + * when all sources terminate. If only one source ever failed, its error is emitted as-is at the end.
+ *
+ * @param sources the {@code Publisher} sequence of inner {@code CompletableSource}s to switch between + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + * @see #switchOnNext(Publisher) + * @see ReactiveX operators documentation: Switch + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) + public static Completable switchOnNextDelayError(@NonNull Publisher<@NonNull ? extends CompletableSource> sources) { + Objects.requireNonNull(sources, "sources is null"); + return RxJavaPlugins.onAssembly(new FlowableSwitchMapCompletablePublisher<>(sources, Functions.identity(), true)); + } + /** * Returns a {@code Completable} instance which manages a resource along * with a custom {@link CompletableSource} instance while the subscription is active. *

- * + * *

* This overload disposes eagerly before the terminal event is emitted. *

@@ -1028,19 +1217,19 @@ private static NullPointerException toNpe(Throwable ex) { *
* @param the resource type * @param resourceSupplier the {@link Supplier} that returns a resource to be managed. - * @param completableFunction the {@link Function} that given a resource returns a {@code CompletableSource} instance that will be subscribed to - * @param disposer the {@link Consumer} that disposes the resource created by the resource supplier + * @param sourceSupplier the {@link Function} that given a resource returns a {@code CompletableSource} instance that will be subscribed to + * @param resourceCleanup the {@link Consumer} that disposes the resource created by the resource supplier * @return the new {@code Completable} instance - * @throws NullPointerException if {@code resourceSupplier}, {@code completableFunction} - * or {@code disposer} is {@code null} + * @throws NullPointerException if {@code resourceSupplier}, {@code sourceSupplier} + * or {@code resourceCleanup} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Completable using(@NonNull Supplier resourceSupplier, - @NonNull Function completableFunction, - @NonNull Consumer disposer) { - return using(resourceSupplier, completableFunction, disposer, true); + public static <@NonNull R> Completable using(@NonNull Supplier resourceSupplier, + @NonNull Function sourceSupplier, + @NonNull Consumer resourceCleanup) { + return using(resourceSupplier, sourceSupplier, resourceCleanup, true); } /** @@ -1058,31 +1247,31 @@ public static Completable using(@NonNull Supplier resourceSupplier, *
* @param the resource type * @param resourceSupplier the {@link Supplier} that returns a resource to be managed - * @param completableFunction the {@link Function} that given a resource returns a non-{@code null} + * @param sourceSupplier the {@link Function} that given a resource returns a non-{@code null} * {@code CompletableSource} instance that will be subscribed to - * @param disposer the {@link Consumer} that disposes the resource created by the resource supplier + * @param resourceCleanup the {@link Consumer} that disposes the resource created by the resource supplier * @param eager * If {@code true} then resource disposal will happen either on a {@code dispose()} call before the upstream is disposed * or just before the emission of a terminal event ({@code onComplete} or {@code onError}). * If {@code false} the resource disposal will happen either on a {@code dispose()} call after the upstream is disposed * or just after the emission of a terminal event ({@code onComplete} or {@code onError}). * @return the new {@code Completable} instance - * @throws NullPointerException if {@code resourceSupplier}, {@code completableFunction} - * or {@code disposer} is {@code null} + * @throws NullPointerException if {@code resourceSupplier}, {@code sourceSupplier} + * or {@code resourceCleanup} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Completable using( + public static <@NonNull R> Completable using( @NonNull Supplier resourceSupplier, - @NonNull Function completableFunction, - @NonNull Consumer disposer, + @NonNull Function sourceSupplier, + @NonNull Consumer resourceCleanup, boolean eager) { Objects.requireNonNull(resourceSupplier, "resourceSupplier is null"); - Objects.requireNonNull(completableFunction, "completableFunction is null"); - Objects.requireNonNull(disposer, "disposer is null"); + Objects.requireNonNull(sourceSupplier, "sourceSupplier is null"); + Objects.requireNonNull(resourceCleanup, "resourceCleanup is null"); - return RxJavaPlugins.onAssembly(new CompletableUsing<>(resourceSupplier, completableFunction, disposer, eager)); + return RxJavaPlugins.onAssembly(new CompletableUsing<>(resourceSupplier, sourceSupplier, resourceCleanup, eager)); } /** @@ -1095,7 +1284,7 @@ public static Completable using( *
{@code wrap} does not operate by default on a particular {@link Scheduler}.
*
* @param source the source to wrap - * @return the source or its wrapper {@code Completable} + * @return the new wrapped or cast {@code Completable} instance * @throws NullPointerException if {@code source} is {@code null} */ @CheckReturnValue @@ -1113,7 +1302,7 @@ public static Completable wrap(@NonNull CompletableSource source) { * Returns a {@code Completable} that emits the a terminated event of either this {@code Completable} * or the other {@link CompletableSource}, whichever fires first. *

- * + * *

*
Scheduler:
*
{@code ambWith} does not operate by default on a particular {@link Scheduler}.
@@ -1214,7 +1403,7 @@ public final Completable ambWith(@NonNull CompletableSource other) { * propagated to the downstream observer and will result in skipping the subscription to the next * {@code MaybeSource}. *

- * + * *

*
Scheduler:
*
{@code andThen} does not operate by default on a particular {@link Scheduler}.
@@ -1262,7 +1451,7 @@ public final Completable andThen(@NonNull CompletableSource next) { * Subscribes to and awaits the termination of this {@code Completable} instance in a blocking manner and * rethrows any exception emitted. *

- * + * *

*
Scheduler:
*
{@code blockingAwait} does not operate by default on a particular {@link Scheduler}.
@@ -1309,6 +1498,106 @@ public final boolean blockingAwait(long timeout, @NonNull TimeUnit unit) { return observer.blockingAwait(timeout, unit); } + /** + * Subscribes to the current {@code Completable} and blocks the current thread until it terminates. + *

+ * + *

+ *
Scheduler:
+ *
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If the current {@code Completable} signals an error, + * the {@link Throwable} is routed to the global error handler via {@link RxJavaPlugins#onError(Throwable)}. + * If the current thread is interrupted, an {@link InterruptedException} is routed to the same global error handler. + *
+ *
+ * @since 3.0.0 + * @see #blockingSubscribe(Action) + * @see #blockingSubscribe(Action, Consumer) + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void blockingSubscribe() { + blockingSubscribe(Functions.EMPTY_ACTION, Functions.ERROR_CONSUMER); + } + + /** + * Subscribes to the current {@code Completable} and calls given {@code onComplete} callback on the current thread + * when it completes normally. + *

+ * + *

+ *
Scheduler:
+ *
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If either the current {@code Completable} signals an error or {@code onComplete} throws, + * the respective {@link Throwable} is routed to the global error handler via {@link RxJavaPlugins#onError(Throwable)}. + * If the current thread is interrupted, an {@link InterruptedException} is routed to the same global error handler. + *
+ *
+ * @param onComplete the {@link Action} to call if the current {@code Completable} completes normally + * @throws NullPointerException if {@code onComplete} is {@code null} + * @since 3.0.0 + * @see #blockingSubscribe(Action, Consumer) + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void blockingSubscribe(@NonNull Action onComplete) { + blockingSubscribe(onComplete, Functions.ERROR_CONSUMER); + } + + /** + * Subscribes to the current {@code Completable} and calls the appropriate callback on the current thread + * when it terminates. + *

+ * + *

+ *
Scheduler:
+ *
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If either {@code onComplete} or {@code onError} throw, the {@link Throwable} is routed to the + * global error handler via {@link RxJavaPlugins#onError(Throwable)}. + * If the current thread is interrupted, the {@code onError} consumer is called with an {@link InterruptedException}. + *
+ *
+ * @param onComplete the {@link Action} to call if the current {@code Completable} completes normally + * @param onError the {@link Consumer} to call if the current {@code Completable} signals an error + * @throws NullPointerException if {@code onComplete} or {@code onError} is {@code null} + * @since 3.0.0 + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void blockingSubscribe(@NonNull Action onComplete, @NonNull Consumer onError) { + Objects.requireNonNull(onComplete, "onComplete is null"); + Objects.requireNonNull(onError, "onError is null"); + BlockingMultiObserver observer = new BlockingMultiObserver<>(); + subscribe(observer); + observer.blockingConsume(Functions.emptyConsumer(), onError, onComplete); + } + + /** + * Subscribes to the current {@code Completable} and calls the appropriate {@link CompletableObserver} method on the current thread. + *

+ * + *

+ *
Scheduler:
+ *
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
An {@code onError} signal is delivered to the {@link CompletableObserver#onError(Throwable)} method. + * If any of the {@code CompletableObserver}'s methods throw, the {@link RuntimeException} is propagated to the caller of this method. + * If the current thread is interrupted, an {@link InterruptedException} is delivered to {@code observer.onError}. + *
+ *
+ * @param observer the {@code CompletableObserver} to call methods on the current thread + * @throws NullPointerException if {@code observer} is {@code null} + * @since 3.0.0 + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void blockingSubscribe(@NonNull CompletableObserver observer) { + Objects.requireNonNull(observer, "observer is null"); + BlockingDisposableMultiObserver blockingObserver = new BlockingDisposableMultiObserver<>(); + observer.onSubscribe(blockingObserver); + subscribe(blockingObserver); + blockingObserver.blockingConsume(observer); + } + /** * Subscribes to this {@code Completable} only once, when the first {@link CompletableObserver} * subscribes to the result {@code Completable}, caches its terminal event @@ -1343,7 +1632,7 @@ public final Completable cache() { *
{@code compose} does not operate by default on a particular {@link Scheduler}.
*
* @param transformer the transformer function, not {@code null} - * @return a {@code Completable} wrapping the {@code CompletableSource} returned by the function via {@link #wrap(CompletableSource)} + * @return the new {@code Completable} instance * @throws NullPointerException if {@code transformer} is {@code null} */ @CheckReturnValue @@ -1384,12 +1673,12 @@ public final Completable concatWith(@NonNull CompletableSource other) { /** * Returns a {@code Completable} which delays the emission of the completion event by the given time. *

- * + * *

*
Scheduler:
*
{@code delay} does operate by default on the {@code computation} {@link Scheduler}.
*
- * @param delay the delay time + * @param time the delay time * @param unit the delay unit * @return the new {@code Completable} instance * @throws NullPointerException if {@code unit} is {@code null} @@ -1397,8 +1686,8 @@ public final Completable concatWith(@NonNull CompletableSource other) { @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Completable delay(long delay, @NonNull TimeUnit unit) { - return delay(delay, unit, Schedulers.computation(), false); + public final Completable delay(long time, @NonNull TimeUnit unit) { + return delay(time, unit, Schedulers.computation(), false); } /** @@ -1410,7 +1699,7 @@ public final Completable delay(long delay, @NonNull TimeUnit unit) { *
Scheduler:
*
{@code delay} operates on the {@code Scheduler} you specify.
*
- * @param delay the delay time + * @param time the delay time * @param unit the delay unit * @param scheduler the {@code Scheduler} to run the delayed completion on * @return the new {@code Completable} instance @@ -1419,8 +1708,8 @@ public final Completable delay(long delay, @NonNull TimeUnit unit) { @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Completable delay(long delay, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return delay(delay, unit, scheduler, false); + public final Completable delay(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + return delay(time, unit, scheduler, false); } /** @@ -1432,7 +1721,7 @@ public final Completable delay(long delay, @NonNull TimeUnit unit, @NonNull Sche *
Scheduler:
*
{@code delay} operates on the {@code Scheduler} you specify.
*
- * @param delay the delay time + * @param time the delay time * @param unit the delay unit * @param scheduler the {@code Scheduler} to run the delayed completion on * @param delayError delay the error emission as well? @@ -1442,10 +1731,10 @@ public final Completable delay(long delay, @NonNull TimeUnit unit, @NonNull Sche @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Completable delay(long delay, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError) { + public final Completable delay(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new CompletableDelay(this, delay, unit, scheduler, delayError)); + return RxJavaPlugins.onAssembly(new CompletableDelay(this, time, unit, scheduler, delayError)); } /** @@ -1458,9 +1747,9 @@ public final Completable delay(long delay, @NonNull TimeUnit unit, @NonNull Sche * *

History: 2.2.3 - experimental * - * @param delay the time to delay the subscription + * @param time the time to delay the subscription * @param unit the time unit of {@code delay} - * @return a {@code Completable} that delays the subscription to the upstream by the given amount + * @return the new {@code Completable} instance * @throws NullPointerException if {@code unit} is {@code null} * @since 3.0.0 * @see ReactiveX operators documentation: Delay @@ -1468,8 +1757,8 @@ public final Completable delay(long delay, @NonNull TimeUnit unit, @NonNull Sche @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Completable delaySubscription(long delay, @NonNull TimeUnit unit) { - return delaySubscription(delay, unit, Schedulers.computation()); + public final Completable delaySubscription(long time, @NonNull TimeUnit unit) { + return delaySubscription(time, unit, Schedulers.computation()); } /** @@ -1482,11 +1771,10 @@ public final Completable delaySubscription(long delay, @NonNull TimeUnit unit) { *

You specify which {@code Scheduler} this operator will use.
* *

History: 2.2.3 - experimental - * @param delay the time to delay the subscription + * @param time the time to delay the subscription * @param unit the time unit of {@code delay} * @param scheduler the {@code Scheduler} on which the waiting and subscription will happen - * @return a {@code Completable} that delays the subscription to the upstream by a given - * amount of time, waiting and subscribing on the given {@code Scheduler} + * @return the new {@code Completable} instance * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @since 3.0.0 * @see ReactiveX operators documentation: Delay @@ -1494,8 +1782,8 @@ public final Completable delaySubscription(long delay, @NonNull TimeUnit unit) { @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Completable delaySubscription(long delay, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return Completable.timer(delay, unit, scheduler).andThen(this); + public final Completable delaySubscription(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + return Completable.timer(time, unit, scheduler).andThen(this); } /** @@ -1581,11 +1869,39 @@ public final Completable doOnError(@NonNull Consumer onError) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Completable doOnEvent(@NonNull Consumer onEvent) { + public final Completable doOnEvent(@NonNull Consumer<@Nullable ? super Throwable> onEvent) { Objects.requireNonNull(onEvent, "onEvent is null"); return RxJavaPlugins.onAssembly(new CompletableDoOnEvent(this, onEvent)); } + /** + * Calls the appropriate {@code onXXX} method (shared between all {@link CompletableObserver}s) for the lifecycle events of + * the sequence (subscription, disposal). + *

+ * + *

+ *
Scheduler:
+ *
{@code doOnLifecycle} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param onSubscribe + * a {@link Consumer} called with the {@link Disposable} sent via {@link CompletableObserver#onSubscribe(Disposable)} + * @param onDispose + * called when the downstream disposes the {@code Disposable} via {@code dispose()} + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code onSubscribe} or {@code onDispose} is {@code null} + * @see ReactiveX operators documentation: Do + * @since 3.0.0 + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Completable doOnLifecycle(@NonNull Consumer onSubscribe, @NonNull Action onDispose) { + return doOnLifecycle(onSubscribe, Functions.emptyConsumer(), + Functions.EMPTY_ACTION, Functions.EMPTY_ACTION, + Functions.EMPTY_ACTION, onDispose); + } + /** * Returns a {@code Completable} instance that calls the various callbacks upon the specific * lifecycle events. @@ -1593,11 +1909,12 @@ public final Completable doOnEvent(@NonNull Consumer onEvent) *
Scheduler:
*
{@code doOnLifecycle} does not operate by default on a particular {@link Scheduler}.
* - * @param onSubscribe the consumer called when a {@link CompletableObserver} subscribes. - * @param onError the consumer called when this emits an {@code onError} event - * @param onComplete the runnable called just before when the upstream {@code Completable} completes normally - * @param onAfterTerminate the runnable called after this {@code Completable} completes normally - * @param onDispose the {@link Runnable} called when the downstream disposes the subscription + * @param onSubscribe the {@link Consumer} called when a {@link CompletableObserver} subscribes. + * @param onError the {@code Consumer} called when this emits an {@code onError} event + * @param onComplete the {@link Action} called just before when the current {@code Completable} completes normally + * @param onTerminate the {@code Action} called just before this {@code Completable} terminates + * @param onAfterTerminate the {@code Action} called after this {@code Completable} completes normally + * @param onDispose the {@code Action} called when the downstream disposes the subscription * @return the new {@code Completable} instance * @throws NullPointerException if {@code onSubscribe}, {@code onError}, {@code onComplete} * {@code onTerminate}, {@code onAfterTerminate} or {@code onDispose} is {@code null} @@ -1647,13 +1964,14 @@ public final Completable doOnSubscribe(@NonNull Consumer onS * Returns a {@code Completable} instance that calls the given {@code onTerminate} {@link Action} just before this {@code Completable} * completes normally or with an exception. *

- * + * *

*
Scheduler:
*
{@code doOnTerminate} does not operate by default on a particular {@link Scheduler}.
*
* @param onTerminate the {@code Action} to call just before this {@code Completable} terminates * @return the new {@code Completable} instance + * @throws NullPointerException if {@code onTerminate} is {@code null} * @see #doFinally(Action) */ @CheckReturnValue @@ -1669,13 +1987,14 @@ public final Completable doOnTerminate(@NonNull Action onTerminate) { * Returns a {@code Completable} instance that calls the given {@code onAfterTerminate} {@link Action} after this {@code Completable} * completes normally or with an exception. *

- * + * *

*
Scheduler:
*
{@code doAfterTerminate} does not operate by default on a particular {@link Scheduler}.
*
* @param onAfterTerminate the {@code Action} to call after this {@code Completable} terminates * @return the new {@code Completable} instance + * @throws NullPointerException if {@code onAfterTerminate} is {@code null} * @see #doFinally(Action) */ @CheckReturnValue @@ -1831,7 +2150,7 @@ public final Completable doFinally(@NonNull Action onFinally) { *

* Note also that it is not possible to stop the subscription phase in {@code lift()} as the {@code apply()} method * requires a non-{@code null} {@code CompletableObserver} instance to be returned, which is then unconditionally subscribed to - * the upstream {@code Completable}. For example, if the operator decided there is no reason to subscribe to the + * the current {@code Completable}. For example, if the operator decided there is no reason to subscribe to the * upstream source because of some optimization possibility or a failure to prepare the operator, it still has to * return a {@code CompletableObserver} that should immediately dispose the upstream's {@link Disposable} in its * {@code onSubscribe} method. Again, using a {@code CompletableTransformer} and extending the {@code Completable} is @@ -1862,7 +2181,7 @@ public final Completable lift(@NonNull CompletableOperator onLift) { * Maps the signal types of this {@code Completable} into a {@link Notification} of the same kind * and emits it as a single success value to downstream. *

- * + * *

*
Scheduler:
*
{@code materialize} does not operate by default on a particular {@link Scheduler}.
@@ -1876,7 +2195,7 @@ public final Completable lift(@NonNull CompletableOperator onLift) { @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single> materialize() { + public final <@NonNull T> Single> materialize() { return RxJavaPlugins.onAssembly(new CompletableMaterialize<>(this)); } @@ -1972,17 +2291,103 @@ public final Completable onErrorComplete(@NonNull Predicate p *
Scheduler:
*
{@code onErrorResumeNext} does not operate by default on a particular {@link Scheduler}.
*
- * @param errorMapper the {@code mapper} {@code Function} that takes the error and should return a {@code CompletableSource} as + * @param fallbackSupplier the {@code mapper} {@code Function} that takes the error and should return a {@code CompletableSource} as * continuation. * @return the new {@code Completable} instance - * @throws NullPointerException if {@code errorMapper} is {@code null} + * @throws NullPointerException if {@code fallbackSupplier} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Completable onErrorResumeNext(@NonNull Function errorMapper) { - Objects.requireNonNull(errorMapper, "errorMapper is null"); - return RxJavaPlugins.onAssembly(new CompletableResumeNext(this, errorMapper)); + public final Completable onErrorResumeNext(@NonNull Function fallbackSupplier) { + Objects.requireNonNull(fallbackSupplier, "fallbackSupplier is null"); + return RxJavaPlugins.onAssembly(new CompletableResumeNext(this, fallbackSupplier)); + } + /** + * Resumes the flow with the given {@link CompletableSource} when the current {@code Completable} fails instead of + * signaling the error via {@code onError}. + *

+ * + *

+ * You can use this to prevent errors from propagating or to supply fallback data should errors be + * encountered. + *

+ *
Scheduler:
+ *
{@code onErrorResumeWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param fallback + * the next {@code CompletableSource} that will take over if the current {@code Completable} encounters + * an error + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code fallback} is {@code null} + * @see ReactiveX operators documentation: Catch + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final Completable onErrorResumeWith(@NonNull CompletableSource fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return onErrorResumeNext(Functions.justFunction(fallback)); + } + + /** + * Ends the flow with a success item returned by a function for the {@link Throwable} error signaled by the current + * {@code Completable} instead of signaling the error via {@code onError}. + *

+ * + *

+ * You can use this to prevent errors from propagating or to supply fallback data should errors be + * encountered. + *

+ *
Scheduler:
+ *
{@code onErrorReturn} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param the item type to return on error + * @param itemSupplier + * a function that returns a single value that will be emitted as success value + * the current {@code Completable} signals an {@code onError} event + * @return the new {@link Maybe} instance + * @throws NullPointerException if {@code itemSupplier} is {@code null} + * @see ReactiveX operators documentation: Catch + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final <@NonNull T> Maybe onErrorReturn(@NonNull Function itemSupplier) { + Objects.requireNonNull(itemSupplier, "itemSupplier is null"); + return RxJavaPlugins.onAssembly(new CompletableOnErrorReturn<>(this, itemSupplier)); + } + + /** + * Ends the flow with the given success item when the current {@code Completable} + * fails instead of signaling the error via {@code onError}. + *

+ * + *

+ * You can use this to prevent errors from propagating or to supply fallback data should errors be + * encountered. + *

+ *
Scheduler:
+ *
{@code onErrorReturnItem} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param the item type to return on error + * @param item + * the value that is emitted as {@code onSuccess} in case the current {@code Completable} signals an {@code onError} + * @return the new {@link Maybe} instance + * @throws NullPointerException if {@code item} is {@code null} + * @see ReactiveX operators documentation: Catch + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final <@NonNull T> Maybe onErrorReturnItem(@NonNull T item) { + Objects.requireNonNull(item, "item is null"); + return onErrorReturn(Functions.justFunction(item)); } /** @@ -1995,8 +2400,7 @@ public final Completable onErrorResumeNext(@NonNull Function{@code onTerminateDetach} does not operate by default on a particular {@link Scheduler}. * *

History: 2.1.5 - experimental - * @return a {@code Completable} which {@code null}s out references to the upstream producer and downstream {@code CompletableObserver} if - * the sequence is terminated or downstream calls {@code dispose()} + * @return the new {@code Completable} instance * @since 2.2 */ @CheckReturnValue @@ -2033,7 +2437,7 @@ public final Completable repeat() { * * @param times the number of times the re-subscription should happen * @return the new {@code Completable} instance - * @throws IllegalArgumentException if times is less than zero + * @throws IllegalArgumentException if {@code times} is negative */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -2075,12 +2479,12 @@ public final Completable repeatUntil(@NonNull BooleanSupplier stop) { * this {@code Completable} and returns a {@code Publisher} that emits items for repeating or completes to indicate the * repetition should stop * @return the new {@code Completable} instance - * @throws NullPointerException if {@code stop} is {@code null} + * @throws NullPointerException if {@code handler} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Completable repeatWhen(@NonNull Function, ? extends Publisher> handler) { + public final Completable repeatWhen(@NonNull Function, @NonNull ? extends Publisher<@NonNull ?>> handler) { return fromPublisher(toFlowable().repeatWhen(handler)); } @@ -2188,6 +2592,27 @@ public final Completable retry(@NonNull Predicate predicate) return fromPublisher(toFlowable().retry(predicate)); } + /** + * Retries until the given stop function returns {@code true}. + *

+ * + *

+ *
Scheduler:
+ *
{@code retryUntil} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param stop the function that should return {@code true} to stop retrying + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code stop} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final Completable retryUntil(@NonNull BooleanSupplier stop) { + Objects.requireNonNull(stop, "stop is null"); + return retry(Long.MAX_VALUE, Functions.predicateReverseFor(stop)); + } + /** * Returns a {@code Completable} which given a {@link Publisher} and when this {@code Completable} emits an error, delivers * that error through a {@link Flowable} and the {@code Publisher} should signal a value indicating a retry in response @@ -2231,13 +2656,38 @@ public final Completable retry(@NonNull Predicate predicate) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Completable retryWhen(@NonNull Function, ? extends Publisher> handler) { + public final Completable retryWhen(@NonNull Function, @NonNull ? extends Publisher<@NonNull ?>> handler) { return fromPublisher(toFlowable().retryWhen(handler)); } + /** + * Wraps the given {@link CompletableObserver}, catches any {@link RuntimeException}s thrown by its + * {@link CompletableObserver#onSubscribe(Disposable)}, {@link CompletableObserver#onError(Throwable)} + * or {@link CompletableObserver#onComplete()} methods and routes those to the global + * error handler via {@link RxJavaPlugins#onError(Throwable)}. + *

+ * By default, the {@code Completable} protocol forbids the {@code onXXX} methods to throw, but some + * {@code CompletableObserver} implementation may do it anyway, causing undefined behavior in the + * upstream. This method and the underlying safe wrapper ensures such misbehaving consumers don't + * disrupt the protocol. + *

+ *
Scheduler:
+ *
{@code safeSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param observer the potentially misbehaving {@code CompletableObserver} + * @throws NullPointerException if {@code observer} is {@code null} + * @see #subscribe(Action, Consumer) + * @since 3.0.0 + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void safeSubscribe(@NonNull CompletableObserver observer) { + Objects.requireNonNull(observer, "observer is null"); + subscribe(new SafeCompletableObserver(observer)); + } + /** * Returns a {@code Completable} which first runs the other {@link CompletableSource} - * then this {@code Completable} if the other completed normally. + * then the current {@code Completable} if the other completed normally. *

* *

@@ -2256,9 +2706,61 @@ public final Completable startWith(@NonNull CompletableSource other) { return concatArray(other, this); } + /** + * Returns a {@link Flowable} which first runs the other {@link SingleSource} + * then the current {@code Completable} if the other succeeded normally. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Flowable} honors the backpressure of the downstream consumer.
+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the element type of the {@code other} {@code SingleSource}. + * @param other the other {@code SingleSource} to run first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.FULL) + public final <@NonNull T> Flowable startWith(@NonNull SingleSource other) { + Objects.requireNonNull(other, "other is null"); + return Flowable.concat(Single.wrap(other).toFlowable(), toFlowable()); + } + + /** + * Returns a {@link Flowable} which first runs the other {@link MaybeSource} + * then the current {@code Completable} if the other succeeded or completed normally. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Flowable} honors the backpressure of the downstream consumer.
+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the element type of the {@code other} {@code MaybeSource}. + * @param other the other {@code MaybeSource} to run first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.FULL) + public final <@NonNull T> Flowable startWith(@NonNull MaybeSource other) { + Objects.requireNonNull(other, "other is null"); + return Flowable.concat(Maybe.wrap(other).toFlowable(), toFlowable()); + } + /** * Returns an {@link Observable} which first delivers the events - * of the other {@link ObservableSource} then runs this {@code Completable}. + * of the other {@link ObservableSource} then runs the current {@code Completable}. *

* *

@@ -2273,13 +2775,14 @@ public final Completable startWith(@NonNull CompletableSource other) { @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Observable startWith(@NonNull ObservableSource other) { + public final <@NonNull T> Observable startWith(@NonNull ObservableSource other) { Objects.requireNonNull(other, "other is null"); return Observable.wrap(other).concatWith(this.toObservable()); } + /** * Returns a {@link Flowable} which first delivers the events - * of the other {@link Publisher} then runs this {@code Completable}. + * of the other {@link Publisher} then runs the current {@code Completable}. *

* *

@@ -2298,7 +2801,7 @@ public final Observable startWith(@NonNull ObservableSource other) { @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable startWith(@NonNull Publisher other) { + public final <@NonNull T> Flowable startWith(@NonNull Publisher other) { Objects.requireNonNull(other, "other is null"); return this.toFlowable().startWith(other); } @@ -2333,7 +2836,8 @@ public final Completable hide() { *
Scheduler:
*
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
- * @return the {@code Disposable} that allows disposing the subscription + * @return the new {@code Disposable} that can be used for disposing the subscription at any time + * @see #subscribe(Action, Consumer, DisposableContainer) */ @SchedulerSupport(SchedulerSupport.NONE) @NonNull @@ -2417,8 +2921,9 @@ public final void subscribe(@NonNull CompletableObserver observer) { *
* @param onComplete the {@link Action} that is called if the {@code Completable} completes normally * @param onError the {@link Consumer} that is called if this {@code Completable} emits an error - * @return the {@link Disposable} that can be used for disposing the subscription asynchronously + * @return the new {@link Disposable} that can be used for disposing the subscription at any time * @throws NullPointerException if {@code onComplete} or {@code onError} is {@code null} + * @see #subscribe(Action, Consumer, DisposableContainer) */ @CheckReturnValue @NonNull @@ -2432,6 +2937,44 @@ public final Disposable subscribe(@NonNull Action onComplete, @NonNull Consumer< return observer; } + /** + * Wraps the given onXXX callbacks into a {@link Disposable} {@link CompletableObserver}, + * adds it to the given {@link DisposableContainer} and ensures, that if the upstream + * terminates or this particular {@code Disposable} is disposed, the {@code CompletableObserver} is removed + * from the given composite. + *

+ * The {@code CompletableObserver} will be removed after the callback for the terminal event has been invoked. + *

+ *
Scheduler:
+ *
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param onError the callback for an upstream error + * @param onComplete the callback for an upstream completion + * @param container the {@code DisposableContainer} (such as {@link CompositeDisposable}) to add and remove the + * created {@code Disposable} {@code CompletableObserver} + * @return the {@code Disposable} that allows disposing the particular subscription. + * @throws NullPointerException + * if {@code onComplete}, {@code onError} + * or {@code container} is {@code null} + * @since 3.1.0 + */ + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Disposable subscribe( + @NonNull Action onComplete, + @NonNull Consumer onError, + @NonNull DisposableContainer container) { + Objects.requireNonNull(onComplete, "onComplete is null"); + Objects.requireNonNull(onError, "onError is null"); + Objects.requireNonNull(container, "container is null"); + + DisposableAutoReleaseMultiObserver observer = new DisposableAutoReleaseMultiObserver<>( + container, Functions.emptyConsumer(), onError, onComplete); + container.add(observer); + subscribe(observer); + return observer; + } + /** * Subscribes to this {@code Completable} and calls the given {@link Action} when this {@code Completable} * completes normally. @@ -2446,18 +2989,15 @@ public final Disposable subscribe(@NonNull Action onComplete, @NonNull Consumer< *
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
* @param onComplete the {@code Action} called when this {@code Completable} completes normally - * @return the {@link Disposable} that allows disposing the subscription + * @return the new {@link Disposable} that can be used for disposing the subscription at any time * @throws NullPointerException if {@code onComplete} is {@code null} + * @see #subscribe(Action, Consumer, DisposableContainer) */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) public final Disposable subscribe(@NonNull Action onComplete) { - Objects.requireNonNull(onComplete, "onComplete is null"); - - CallbackCompletableObserver observer = new CallbackCompletableObserver(onComplete); - subscribe(observer); - return observer; + return subscribe(onComplete, Functions.ON_ERROR_MISSING); } /** @@ -2543,16 +3083,16 @@ public final Completable timeout(long timeout, @NonNull TimeUnit unit) { * * @param timeout the timeout value * @param unit the unit of {@code timeout} - * @param other the other {@code CompletableSource} instance to switch to in case of a timeout + * @param fallback the other {@code CompletableSource} instance to switch to in case of a timeout * @return the new {@code Completable} instance - * @throws NullPointerException if {@code unit} or {@code other} is {@code null} + * @throws NullPointerException if {@code unit} or {@code fallback} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.COMPUTATION) - public final Completable timeout(long timeout, @NonNull TimeUnit unit, @NonNull CompletableSource other) { - Objects.requireNonNull(other, "other is null"); - return timeout0(timeout, unit, Schedulers.computation(), other); + public final Completable timeout(long timeout, @NonNull TimeUnit unit, @NonNull CompletableSource fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return timeout0(timeout, unit, Schedulers.computation(), fallback); } /** @@ -2592,16 +3132,16 @@ public final Completable timeout(long timeout, @NonNull TimeUnit unit, @NonNull * @param timeout the timeout value * @param unit the unit of {@code timeout} * @param scheduler the {@code Scheduler} to use to wait for completion - * @param other the other {@code Completable} instance to switch to in case of a timeout + * @param fallback the other {@code Completable} instance to switch to in case of a timeout * @return the new {@code Completable} instance - * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code other} is {@code null} + * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code fallback} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Completable timeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull CompletableSource other) { - Objects.requireNonNull(other, "other is null"); - return timeout0(timeout, unit, scheduler, other); + public final Completable timeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull CompletableSource fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return timeout0(timeout, unit, scheduler, fallback); } /** @@ -2615,18 +3155,18 @@ public final Completable timeout(long timeout, @NonNull TimeUnit unit, @NonNull * @param timeout the timeout value * @param unit the unit of {@code timeout} * @param scheduler the {@code Scheduler} to use to wait for completion - * @param other the other {@code Completable} instance to switch to in case of a timeout, + * @param fallback the other {@code Completable} instance to switch to in case of a timeout, * if {@code null} a {@link TimeoutException} is emitted instead * @return the new {@code Completable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} + * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code fallback} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.CUSTOM) - private Completable timeout0(long timeout, TimeUnit unit, Scheduler scheduler, CompletableSource other) { + private Completable timeout0(long timeout, TimeUnit unit, Scheduler scheduler, CompletableSource fallback) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new CompletableTimeout(this, timeout, unit, scheduler, other)); + return RxJavaPlugins.onAssembly(new CompletableTimeout(this, timeout, unit, scheduler, fallback)); } /** @@ -2671,12 +3211,34 @@ public final R to(@NonNull CompletableConverter converter) { @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable toFlowable() { + public final <@NonNull T> Flowable toFlowable() { if (this instanceof FuseToFlowable) { return ((FuseToFlowable)this).fuseToFlowable(); } return RxJavaPlugins.onAssembly(new CompletableToFlowable<>(this)); } + /** + * Returns a {@link Future} representing the termination of the current {@code Completable} + * via a {@code null} value. + *

+ * + *

+ * Cancelling the {@code Future} will cancel the subscription to the current {@code Completable}. + *

+ *
Scheduler:
+ *
{@code toFuture} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @return the new {@code Future} instance + * @see ReactiveX documentation: To + * @since 3.0.0 + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Future toFuture() { + return subscribeWith(new FutureMultiObserver<>()); + } /** * Converts this {@code Completable} into a {@link Maybe}. @@ -2688,14 +3250,13 @@ public final Flowable toFlowable() { * * * @param the value type - * @return a {@code Maybe} that only calls {@code onComplete} or {@code onError}, based on which one is - * called by the source {@code Completable}. + * @return the new {@code Maybe} instance */ @CheckReturnValue @SuppressWarnings("unchecked") @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Maybe toMaybe() { + public final <@NonNull T> Maybe toMaybe() { if (this instanceof FuseToMaybe) { return ((FuseToMaybe)this).fuseToMaybe(); } @@ -2718,7 +3279,7 @@ public final Maybe toMaybe() { @SuppressWarnings("unchecked") @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable toObservable() { + public final <@NonNull T> Observable toObservable() { if (this instanceof FuseToObservable) { return ((FuseToObservable)this).fuseToObservable(); } @@ -2850,7 +3411,7 @@ public final TestObserver test(boolean dispose) { * *

* Note that the operator takes an already instantiated, running or terminated {@code CompletionStage}. - * If the optional is to be created per consumer upon subscription, use {@link #defer(Supplier)} + * If the {@code CompletionStage} is to be created per consumer upon subscription, use {@link #defer(Supplier)} * around {@code fromCompletionStage}: *


      * Maybe.defer(() -> Completable.fromCompletionStage(createCompletionStage()));
@@ -2905,7 +3466,7 @@ public static Completable fromCompletionStage(@NonNull CompletionStage stage)
     @CheckReturnValue
     @SchedulerSupport(SchedulerSupport.NONE)
     @NonNull
-    public final  CompletionStage toCompletionStage(@Nullable T defaultItem) {
+    public final <@Nullable T> CompletionStage toCompletionStage(T defaultItem) {
         return subscribeWith(new CompletionStageConsumer<>(true, defaultItem));
     }
 }
diff --git a/src/main/java/io/reactivex/rxjava3/core/CompletableConverter.java b/src/main/java/io/reactivex/rxjava3/core/CompletableConverter.java
index bcc00f088b6..a213c6f5abc 100644
--- a/src/main/java/io/reactivex/rxjava3/core/CompletableConverter.java
+++ b/src/main/java/io/reactivex/rxjava3/core/CompletableConverter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -23,13 +23,12 @@
  * @since 2.2
  */
 @FunctionalInterface
-public interface CompletableConverter {
+public interface CompletableConverter<@NonNull R> {
     /**
      * Applies a function to the upstream Completable and returns a converted value of type {@code R}.
      *
      * @param upstream the upstream Completable instance
      * @return the converted value
      */
-    @NonNull
     R apply(@NonNull Completable upstream);
 }
diff --git a/src/main/java/io/reactivex/rxjava3/core/CompletableEmitter.java b/src/main/java/io/reactivex/rxjava3/core/CompletableEmitter.java
index 5ebb4e1877e..2c5a9811c4e 100644
--- a/src/main/java/io/reactivex/rxjava3/core/CompletableEmitter.java
+++ b/src/main/java/io/reactivex/rxjava3/core/CompletableEmitter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
diff --git a/src/main/java/io/reactivex/rxjava3/core/CompletableObserver.java b/src/main/java/io/reactivex/rxjava3/core/CompletableObserver.java
index 7c01ebfee1f..93393070477 100644
--- a/src/main/java/io/reactivex/rxjava3/core/CompletableObserver.java
+++ b/src/main/java/io/reactivex/rxjava3/core/CompletableObserver.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
diff --git a/src/main/java/io/reactivex/rxjava3/core/CompletableOnSubscribe.java b/src/main/java/io/reactivex/rxjava3/core/CompletableOnSubscribe.java
index 70d79e62b69..e73fae2d5ce 100644
--- a/src/main/java/io/reactivex/rxjava3/core/CompletableOnSubscribe.java
+++ b/src/main/java/io/reactivex/rxjava3/core/CompletableOnSubscribe.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -10,13 +10,14 @@
  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
  * the License for the specific language governing permissions and limitations under the License.
  */
+
 package io.reactivex.rxjava3.core;
 
 import io.reactivex.rxjava3.annotations.NonNull;
 
 /**
  * A functional interface that has a {@code subscribe()} method that receives
- * an instance of a {@link CompletableEmitter} instance that allows pushing
+ * a {@link CompletableEmitter} instance that allows pushing
  * an event in a cancellation-safe manner.
  */
 @FunctionalInterface
diff --git a/src/main/java/io/reactivex/rxjava3/core/CompletableOperator.java b/src/main/java/io/reactivex/rxjava3/core/CompletableOperator.java
index e9b1df83cbb..f06a94f36a8 100644
--- a/src/main/java/io/reactivex/rxjava3/core/CompletableOperator.java
+++ b/src/main/java/io/reactivex/rxjava3/core/CompletableOperator.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
diff --git a/src/main/java/io/reactivex/rxjava3/core/CompletableSource.java b/src/main/java/io/reactivex/rxjava3/core/CompletableSource.java
index 58edf9471c4..90d3853b8a1 100644
--- a/src/main/java/io/reactivex/rxjava3/core/CompletableSource.java
+++ b/src/main/java/io/reactivex/rxjava3/core/CompletableSource.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -10,6 +10,7 @@
  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
  * the License for the specific language governing permissions and limitations under the License.
  */
+
 package io.reactivex.rxjava3.core;
 
 import io.reactivex.rxjava3.annotations.NonNull;
diff --git a/src/main/java/io/reactivex/rxjava3/core/CompletableTransformer.java b/src/main/java/io/reactivex/rxjava3/core/CompletableTransformer.java
index 98a9e2aa19b..2887c4717c6 100644
--- a/src/main/java/io/reactivex/rxjava3/core/CompletableTransformer.java
+++ b/src/main/java/io/reactivex/rxjava3/core/CompletableTransformer.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
diff --git a/src/main/java/io/reactivex/rxjava3/core/Emitter.java b/src/main/java/io/reactivex/rxjava3/core/Emitter.java
index 0fc2b47c0d5..83410f056e0 100644
--- a/src/main/java/io/reactivex/rxjava3/core/Emitter.java
+++ b/src/main/java/io/reactivex/rxjava3/core/Emitter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -10,6 +10,7 @@
  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
  * the License for the specific language governing permissions and limitations under the License.
  */
+
 package io.reactivex.rxjava3.core;
 
 import io.reactivex.rxjava3.annotations.NonNull;
@@ -25,7 +26,7 @@
  *
  * @param  the value type emitted
  */
-public interface Emitter {
+public interface Emitter<@NonNull T> {
 
     /**
      * Signal a normal value.
diff --git a/src/main/java/io/reactivex/rxjava3/core/Flowable.java b/src/main/java/io/reactivex/rxjava3/core/Flowable.java
index c61ea171639..39f3c63b43b 100644
--- a/src/main/java/io/reactivex/rxjava3/core/Flowable.java
+++ b/src/main/java/io/reactivex/rxjava3/core/Flowable.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -10,6 +10,7 @@
  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
  * the License for the specific language governing permissions and limitations under the License.
  */
+
 package io.reactivex.rxjava3.core;
 
 import java.util.*;
@@ -19,19 +20,21 @@
 import org.reactivestreams.*;
 
 import io.reactivex.rxjava3.annotations.*;
-import io.reactivex.rxjava3.disposables.Disposable;
+import io.reactivex.rxjava3.disposables.*;
 import io.reactivex.rxjava3.exceptions.*;
 import io.reactivex.rxjava3.flowables.*;
 import io.reactivex.rxjava3.functions.*;
 import io.reactivex.rxjava3.internal.functions.*;
-import io.reactivex.rxjava3.internal.fuseable.ScalarSupplier;
 import io.reactivex.rxjava3.internal.jdk8.*;
 import io.reactivex.rxjava3.internal.operators.flowable.*;
+import io.reactivex.rxjava3.internal.operators.maybe.MaybeToFlowable;
 import io.reactivex.rxjava3.internal.operators.mixed.*;
 import io.reactivex.rxjava3.internal.operators.observable.ObservableFromPublisher;
+import io.reactivex.rxjava3.internal.operators.single.SingleToFlowable;
 import io.reactivex.rxjava3.internal.schedulers.ImmediateThinScheduler;
 import io.reactivex.rxjava3.internal.subscribers.*;
 import io.reactivex.rxjava3.internal.util.*;
+import io.reactivex.rxjava3.operators.ScalarSupplier;
 import io.reactivex.rxjava3.parallel.ParallelFlowable;
 import io.reactivex.rxjava3.plugins.RxJavaPlugins;
 import io.reactivex.rxjava3.schedulers.*;
@@ -51,7 +54,7 @@
  * 

* The documentation for this class makes use of marble diagrams. The following legend explains these diagrams: *

- * + * *

* The {@code Flowable} follows the protocol *


@@ -150,7 +153,7 @@
  * @see ParallelFlowable
  * @see io.reactivex.rxjava3.subscribers.DisposableSubscriber
  */
-public abstract class Flowable implements Publisher {
+public abstract class Flowable<@NonNull T> implements Publisher {
     /** The default buffer size. */
     static final int BUFFER_SIZE;
     static {
@@ -161,28 +164,36 @@ public abstract class Flowable implements Publisher {
      * Mirrors the one {@link Publisher} in an {@link Iterable} of several {@code Publisher}s that first either emits an item or sends
      * a termination notification.
      * 

- * + * + *

+ * When one of the {@code Publisher}s signal an item or terminates first, all subscriptions to the other + * {@code Publisher}s are canceled. *

*
Backpressure:
*
The operator itself doesn't interfere with backpressure which is determined by the winning * {@code Publisher}'s backpressure behavior.
*
Scheduler:
*
{@code amb} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
+ * If any of the losing {@code Publisher}s signals an error, the error is routed to the global + * error handler via {@link RxJavaPlugins#onError(Throwable)}. + *
*
* * @param the common element type * @param sources * an {@code Iterable} of {@code Publisher}s sources competing to react first. A subscription to each {@code Publisher} will * occur in the same order as in this {@code Iterable}. - * @return a {@code Flowable} that emits the same sequence as whichever of the source {@code Publisher}s first - * emitted an item or sent a termination notification + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Amb */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable amb(@NonNull Iterable> sources) { + public static <@NonNull T> Flowable amb(@NonNull Iterable<@NonNull ? extends Publisher> sources) { Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new FlowableAmb<>(null, sources)); } @@ -191,21 +202,29 @@ public static Flowable amb(@NonNull Iterable - * + * + *

+ * When one of the {@code Publisher}s signal an item or terminates first, all subscriptions to the other + * {@code Publisher}s are canceled. *

*
Backpressure:
*
The operator itself doesn't interfere with backpressure which is determined by the winning * {@code Publisher}'s backpressure behavior.
*
Scheduler:
*
{@code ambArray} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
+ * If any of the losing {@code Publisher}s signals an error, the error is routed to the global + * error handler via {@link RxJavaPlugins#onError(Throwable)}. + *
*
* * @param the common element type * @param sources * an array of {@code Publisher} sources competing to react first. A subscription to each {@code Publisher} will * occur in the same order as in this array. - * @return a {@code Flowable} that emits the same sequence as whichever of the source {@code Publisher}s first - * emitted an item or sent a termination notification + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Amb */ @CheckReturnValue @@ -213,7 +232,7 @@ public static Flowable amb(@NonNull Iterable Flowable ambArray(Publisher... sources) { + public static <@NonNull T> Flowable ambArray(@NonNull Publisher... sources) { Objects.requireNonNull(sources, "sources is null"); int len = sources.length; if (len == 0) { @@ -269,15 +288,15 @@ public static int bufferSize() { * the collection of source {@code Publisher}s * @param combiner * the aggregation function used to combine the items emitted by the source {@code Publisher}s - * @return a {@code Flowable} that emits items that are the result of combining the items emitted by the source - * {@code Publisher}s by means of the given aggregation function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SchedulerSupport(SchedulerSupport.NONE) @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @NonNull - public static Flowable combineLatestArray(@NonNull Publisher[] sources, @NonNull Function combiner) { + public static <@NonNull T, @NonNull R> Flowable combineLatestArray(@NonNull Publisher[] sources, @NonNull Function combiner) { return combineLatestArray(sources, combiner, bufferSize()); } @@ -316,15 +335,16 @@ public static int bufferSize() { * the aggregation function used to combine the items emitted by the source {@code Publisher}s * @param bufferSize * the internal buffer size and prefetch amount applied to every source {@code Flowable} - * @return a {@code Flowable} that emits items that are the result of combining the items emitted by the source - * {@code Publisher}s by means of the given aggregation function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} or {@code combiner} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: CombineLatest */ @SchedulerSupport(SchedulerSupport.NONE) @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) - public static Flowable combineLatestArray(@NonNull Publisher[] sources, @NonNull Function combiner, int bufferSize) { + public static <@NonNull T, @NonNull R> Flowable combineLatestArray(@NonNull Publisher[] sources, @NonNull Function combiner, int bufferSize) { Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { return empty(); @@ -367,15 +387,15 @@ public static Flowable combineLatestArray(@NonNull PublisherReactiveX operators documentation: CombineLatest */ @SchedulerSupport(SchedulerSupport.NONE) @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @NonNull - public static Flowable combineLatest(@NonNull Iterable> sources, + public static <@NonNull T, @NonNull R> Flowable combineLatest(@NonNull Iterable<@NonNull ? extends Publisher> sources, @NonNull Function combiner) { return combineLatest(sources, combiner, bufferSize()); } @@ -415,15 +435,16 @@ public static Flowable combineLatestArray(@NonNull PublisherReactiveX operators documentation: CombineLatest */ @SchedulerSupport(SchedulerSupport.NONE) @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) - public static Flowable combineLatest(@NonNull Iterable> sources, + public static <@NonNull T, @NonNull R> Flowable combineLatest(@NonNull Iterable<@NonNull ? extends Publisher> sources, @NonNull Function combiner, int bufferSize) { Objects.requireNonNull(sources, "sources is null"); Objects.requireNonNull(combiner, "combiner is null"); @@ -453,7 +474,7 @@ public static Flowable combineLatest(@NonNull Iterable *
Scheduler:
- *
{@code combineLatestDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
{@code combineLatestArrayDelayError} does not operate by default on a particular {@link Scheduler}.
* * * @param @@ -464,17 +485,17 @@ public static Flowable combineLatest(@NonNull IterableReactiveX operators documentation: CombineLatest */ @SchedulerSupport(SchedulerSupport.NONE) @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @NonNull - public static Flowable combineLatestDelayError(@NonNull Publisher[] sources, + public static <@NonNull T, @NonNull R> Flowable combineLatestArrayDelayError(@NonNull Publisher[] sources, @NonNull Function combiner) { - return combineLatestDelayError(sources, combiner, bufferSize()); + return combineLatestArrayDelayError(sources, combiner, bufferSize()); } /** @@ -500,7 +521,7 @@ public static Flowable combineLatest(@NonNull Iterable *
Scheduler:
- *
{@code combineLatestDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
{@code combineLatestArrayDelayError} does not operate by default on a particular {@link Scheduler}.
* * * @param @@ -513,15 +534,16 @@ public static Flowable combineLatest(@NonNull IterableReactiveX operators documentation: CombineLatest */ @SchedulerSupport(SchedulerSupport.NONE) @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) - public static Flowable combineLatestDelayError(@NonNull Publisher[] sources, + public static <@NonNull T, @NonNull R> Flowable combineLatestArrayDelayError(@NonNull Publisher[] sources, @NonNull Function combiner, int bufferSize) { Objects.requireNonNull(sources, "sources is null"); Objects.requireNonNull(combiner, "combiner is null"); @@ -566,15 +588,15 @@ public static Flowable combineLatest(@NonNull IterableReactiveX operators documentation: CombineLatest */ @SchedulerSupport(SchedulerSupport.NONE) @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @NonNull - public static Flowable combineLatestDelayError(@NonNull Iterable> sources, + public static <@NonNull T, @NonNull R> Flowable combineLatestDelayError(@NonNull Iterable<@NonNull ? extends Publisher> sources, @NonNull Function combiner) { return combineLatestDelayError(sources, combiner, bufferSize()); } @@ -615,15 +637,16 @@ public static Flowable combineLatest(@NonNull IterableReactiveX operators documentation: CombineLatest */ @SchedulerSupport(SchedulerSupport.NONE) @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @NonNull - public static Flowable combineLatestDelayError(@NonNull Iterable> sources, + public static <@NonNull T, @NonNull R> Flowable combineLatestDelayError(@NonNull Iterable<@NonNull ? extends Publisher> sources, @NonNull Function combiner, int bufferSize) { Objects.requireNonNull(sources, "sources is null"); Objects.requireNonNull(combiner, "combiner is null"); @@ -640,7 +663,7 @@ public static Flowable combineLatestDelayError(@NonNull Iterable - * + * *
*
Backpressure:
*
The returned {@code Publisher} honors backpressure from downstream. The source {@code Publisher}s @@ -659,8 +682,8 @@ public static Flowable combineLatestDelayError(@NonNull IterableReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @@ -668,7 +691,7 @@ public static Flowable combineLatestDelayError(@NonNull Iterable Flowable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull R> Flowable combineLatest( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull BiFunction combiner) { Objects.requireNonNull(source1, "source1 is null"); @@ -686,7 +709,7 @@ public static Flowable combineLatest( * resulting sequence terminates immediately (normally or with all the errors accumulated until that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Backpressure:
*
The returned {@code Publisher} honors backpressure from downstream. The source {@code Publisher}s @@ -708,8 +731,8 @@ public static Flowable combineLatest( * the third source {@code Publisher} * @param combiner * the aggregation function used to combine the items emitted by the source {@code Publisher}s - * @return a {@code Flowable} that emits items that are the result of combining the items emitted by the source - * {@code Publisher}s by means of the given aggregation function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @@ -717,7 +740,7 @@ public static Flowable combineLatest( @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull R> Flowable combineLatest( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Function3 combiner) { @@ -737,7 +760,7 @@ public static Flowable combineLatest( * resulting sequence terminates immediately (normally or with all the errors accumulated until that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Backpressure:
*
The returned {@code Publisher} honors backpressure from downstream. The source {@code Publisher}s @@ -762,8 +785,9 @@ public static Flowable combineLatest( * the fourth source {@code Publisher} * @param combiner * the aggregation function used to combine the items emitted by the source {@code Publisher}s - * @return a {@code Flowable} that emits items that are the result of combining the items emitted by the source - * {@code Publisher}s by means of the given aggregation function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @@ -771,7 +795,7 @@ public static Flowable combineLatest( @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull R> Flowable combineLatest( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4, @NonNull Function4 combiner) { @@ -792,7 +816,7 @@ public static Flowable combineLatest( * resulting sequence terminates immediately (normally or with all the errors accumulated until that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Backpressure:
*
The returned {@code Publisher} honors backpressure from downstream. The source {@code Publisher}s @@ -820,8 +844,9 @@ public static Flowable combineLatest( * the fifth source {@code Publisher} * @param combiner * the aggregation function used to combine the items emitted by the source {@code Publisher}s - * @return a {@code Flowable} that emits items that are the result of combining the items emitted by the source - * {@code Publisher}s by means of the given aggregation function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @@ -829,7 +854,7 @@ public static Flowable combineLatest( @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull R> Flowable combineLatest( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4, @NonNull Publisher source5, @@ -852,7 +877,7 @@ public static Flowable combineLatest( * resulting sequence terminates immediately (normally or with all the errors accumulated until that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Backpressure:
*
The returned {@code Publisher} honors backpressure from downstream. The source {@code Publisher}s @@ -883,8 +908,9 @@ public static Flowable combineLatest( * the sixth source {@code Publisher} * @param combiner * the aggregation function used to combine the items emitted by the source {@code Publisher}s - * @return a {@code Flowable} that emits items that are the result of combining the items emitted by the source - * {@code Publisher}s by means of the given aggregation function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @@ -892,7 +918,7 @@ public static Flowable combineLatest( @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull R> Flowable combineLatest( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4, @NonNull Publisher source5, @NonNull Publisher source6, @@ -916,7 +942,7 @@ public static Flowable combineLatest( * resulting sequence terminates immediately (normally or with all the errors accumulated until that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Backpressure:
*
The returned {@code Publisher} honors backpressure from downstream. The source {@code Publisher}s @@ -950,8 +976,10 @@ public static Flowable combineLatest( * the seventh source {@code Publisher} * @param combiner * the aggregation function used to combine the items emitted by the source {@code Publisher}s - * @return a {@code Flowable} that emits items that are the result of combining the items emitted by the source - * {@code Publisher}s by means of the given aggregation function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @@ -959,7 +987,7 @@ public static Flowable combineLatest( @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull R> Flowable combineLatest( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4, @NonNull Publisher source5, @NonNull Publisher source6, @@ -985,7 +1013,7 @@ public static Flowable combineLatest( * resulting sequence terminates immediately (normally or with all the errors accumulated until that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Backpressure:
*
The returned {@code Publisher} honors backpressure from downstream. The source {@code Publisher}s @@ -1022,8 +1050,10 @@ public static Flowable combineLatest( * the eighth source {@code Publisher} * @param combiner * the aggregation function used to combine the items emitted by the source {@code Publisher}s - * @return a {@code Flowable} that emits items that are the result of combining the items emitted by the source - * {@code Publisher}s by means of the given aggregation function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7}, {@code source8} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @@ -1031,7 +1061,7 @@ public static Flowable combineLatest( @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull R> Flowable combineLatest( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4, @NonNull Publisher source5, @NonNull Publisher source6, @@ -1058,7 +1088,7 @@ public static Flowable combineLatest( * resulting sequence terminates immediately (normally or with all the errors accumulated until that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Backpressure:
*
The returned {@code Publisher} honors backpressure from downstream. The source {@code Publisher}s @@ -1098,8 +1128,11 @@ public static Flowable combineLatest( * the ninth source {@code Publisher} * @param combiner * the aggregation function used to combine the items emitted by the source {@code Publisher}s - * @return a {@code Flowable} that emits items that are the result of combining the items emitted by the source - * {@code Publisher}s by means of the given aggregation function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7}, {@code source8}, {@code source9} + * or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @@ -1107,7 +1140,7 @@ public static Flowable combineLatest( @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull T9, @NonNull R> Flowable combineLatest( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4, @NonNull Publisher source5, @NonNull Publisher source6, @@ -1131,26 +1164,27 @@ public static Flowable combineLatest( * Concatenates elements of each {@link Publisher} provided via an {@link Iterable} sequence into a single sequence * of elements without interleaving them. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The {@code Publisher} * sources are expected to honor backpressure as well. * If any of the source {@code Publisher}s violate this, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * {@link IllegalStateException} when that {@code Publisher} completes.
*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
*
* @param the common value type of the sources * @param sources the {@code Iterable} sequence of {@code Publisher}s * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concat(@NonNull Iterable> sources) { + public static <@NonNull T> Flowable concat(@NonNull Iterable<@NonNull ? extends Publisher> sources) { Objects.requireNonNull(sources, "sources is null"); // unlike general sources, fromIterable can only throw on a boundary because it is consumed only there return fromIterable(sources).concatMapDelayError((Function)Functions.identity(), false, 2); @@ -1160,7 +1194,7 @@ public static Flowable concat(@NonNull Iterable - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. Both the outer and inner {@code Publisher} @@ -1174,15 +1208,15 @@ public static Flowable concat(@NonNull Iterable the common element base type * @param sources * a {@code Publisher} that emits {@code Publisher}s - * @return a {@code Flowable} that emits items all of the items emitted by the {@code Publisher}s emitted by - * {@code Publisher}s, one after the other, without interleaving them + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Concat */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable concat(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable concat(@NonNull Publisher<@NonNull ? extends Publisher> sources) { return concat(sources, bufferSize()); } @@ -1190,7 +1224,7 @@ public static Flowable concat(@NonNull Publisher - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. Both the outer and inner {@code Publisher} @@ -1206,8 +1240,9 @@ public static Flowable concat(@NonNull PublisherReactiveX operators documentation: Concat */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -1215,7 +1250,7 @@ public static Flowable concat(@NonNull Publisher Flowable concat(@NonNull Publisher> sources, int prefetch) { + public static <@NonNull T> Flowable concat(@NonNull Publisher<@NonNull ? extends Publisher> sources, int prefetch) { return fromPublisher(sources).concatMap((Function)Functions.identity(), prefetch); } @@ -1223,13 +1258,13 @@ public static Flowable concat(@NonNull Publisher - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. The {@code Publisher} * sources are expected to honor backpressure as well. * If any of the source {@code Publisher}s violate this, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * {@link IllegalStateException} when that source {@code Publisher} completes.
*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
*
@@ -1239,15 +1274,15 @@ public static Flowable concat(@NonNull PublisherReactiveX operators documentation: Concat */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concat(@NonNull Publisher source1, @NonNull Publisher source2) { + public static <@NonNull T> Flowable concat(@NonNull Publisher source1, @NonNull Publisher source2) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); return concatArray(source1, source2); @@ -1257,13 +1292,13 @@ public static Flowable concat(@NonNull Publisher source1, @N * Returns a {@code Flowable} that emits the items emitted by three {@link Publisher}s, one after the other, without * interleaving them. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The {@code Publisher} * sources are expected to honor backpressure as well. * If any of the source {@code Publisher}s violate this, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * {@link IllegalStateException} when that source {@code Publisher} completes.
*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
*
@@ -1275,15 +1310,15 @@ public static Flowable concat(@NonNull Publisher source1, @N * a {@code Publisher} to be concatenated * @param source3 * a {@code Publisher} to be concatenated - * @return a {@code Flowable} that emits items emitted by the three source {@code Publisher}s, one after the other, - * without interleaving them + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} * @see ReactiveX operators documentation: Concat */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concat( + public static <@NonNull T> Flowable concat( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3) { Objects.requireNonNull(source1, "source1 is null"); @@ -1296,13 +1331,13 @@ public static Flowable concat( * Returns a {@code Flowable} that emits the items emitted by four {@link Publisher}s, one after the other, without * interleaving them. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The {@code Publisher} * sources are expected to honor backpressure as well. * If any of the source {@code Publisher}s violate this, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * {@link IllegalStateException} when that source {@code Publisher} completes.
*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
*
@@ -1316,15 +1351,15 @@ public static Flowable concat( * a {@code Publisher} to be concatenated * @param source4 * a {@code Publisher} to be concatenated - * @return a {@code Flowable} that emits items emitted by the four source {@code Publisher}s, one after the other, - * without interleaving them + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} * @see ReactiveX operators documentation: Concat */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concat( + public static <@NonNull T> Flowable concat( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4) { Objects.requireNonNull(source1, "source1 is null"); @@ -1339,27 +1374,28 @@ public static Flowable concat( *

* Note: named this way because of overload conflict with {@code concat(Publisher>}). *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The {@code Publisher} * sources are expected to honor backpressure as well. * If any of the source {@code Publisher}s violate this, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * {@link IllegalStateException} when that source {@code Publisher} completes.
*
Scheduler:
*
{@code concatArray} does not operate by default on a particular {@link Scheduler}.
*
* @param sources the array of source {@code Publisher}s * @param the common base value type - * @return the new {@code Publisher} instance - * @throws NullPointerException if sources is {@code null} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs @NonNull - public static Flowable concatArray(@NonNull Publisher... sources) { + public static <@NonNull T> Flowable concatArray(@NonNull Publisher... sources) { + Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { return empty(); } else @@ -1373,27 +1409,28 @@ public static Flowable concatArray(@NonNull Publisher... sou * Concatenates a variable number of {@link Publisher} sources and delays errors from any of them * till all terminate. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The {@code Publisher} * sources are expected to honor backpressure as well. * If any of the source {@code Publisher}s violate this, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * {@link IllegalStateException} when that source {@code Publisher} completes.
*
Scheduler:
*
{@code concatArrayDelayError} does not operate by default on a particular {@link Scheduler}.
*
* @param sources the array of source {@code Publisher}s * @param the common base value type * @return the new {@code Flowable} instance - * @throws NullPointerException if sources is {@code null} + * @throws NullPointerException if {@code sources} is {@code null} */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs @NonNull - public static Flowable concatArrayDelayError(@NonNull Publisher... sources) { + public static <@NonNull T> Flowable concatArrayDelayError(@NonNull Publisher... sources) { + Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { return empty(); } else @@ -1422,7 +1459,8 @@ public static Flowable concatArrayDelayError(@NonNull Publisher * @param the value type * @param sources an array of {@code Publisher}s that need to be eagerly concatenated - * @return the new {@code Publisher} instance with the specified concatenation behavior + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -1430,7 +1468,7 @@ public static Flowable concatArrayDelayError(@NonNull Publisher Flowable concatArrayEager(@NonNull Publisher... sources) { + public static <@NonNull T> Flowable concatArrayEager(@NonNull Publisher... sources) { return concatArrayEager(bufferSize(), bufferSize(), sources); } @@ -1456,7 +1494,9 @@ public static Flowable concatArrayEager(@NonNull Publisher.. * @param maxConcurrency the maximum number of concurrent subscriptions at a time, {@link Integer#MAX_VALUE} * is interpreted as an indication to subscribe to all sources at once * @param prefetch the number of elements to prefetch from each {@code Publisher} source - * @return the new {@code Publisher} instance with the specified concatenation behavior + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code prefetch} is non-positive * @since 2.0 */ @CheckReturnValue @@ -1465,7 +1505,7 @@ public static Flowable concatArrayEager(@NonNull Publisher.. @SchedulerSupport(SchedulerSupport.NONE) @SuppressWarnings({ "rawtypes", "unchecked" }) @SafeVarargs - public static Flowable concatArrayEager(int maxConcurrency, int prefetch, @NonNull Publisher... sources) { + public static <@NonNull T> Flowable concatArrayEager(int maxConcurrency, int prefetch, @NonNull Publisher... sources) { Objects.requireNonNull(sources, "sources is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); ObjectHelper.verifyPositive(prefetch, "prefetch"); @@ -1493,6 +1533,7 @@ public static Flowable concatArrayEager(int maxConcurrency, int prefetch, * @param the value type * @param sources an array of {@code Publisher}s that need to be eagerly concatenated * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.2.1 - experimental */ @CheckReturnValue @@ -1500,7 +1541,7 @@ public static Flowable concatArrayEager(int maxConcurrency, int prefetch, @BackpressureSupport(BackpressureKind.FULL) @SafeVarargs @NonNull - public static Flowable concatArrayEagerDelayError(@NonNull Publisher... sources) { + public static <@NonNull T> Flowable concatArrayEagerDelayError(@NonNull Publisher... sources) { return concatArrayEagerDelayError(bufferSize(), bufferSize(), sources); } @@ -1528,6 +1569,8 @@ public static Flowable concatArrayEagerDelayError(@NonNull Publisher Flowable concatArrayEagerDelayError(@NonNull Publisher Flowable concatArrayEagerDelayError(int maxConcurrency, int prefetch, @NonNull Publisher... sources) { + public static <@NonNull T> Flowable concatArrayEagerDelayError(int maxConcurrency, int prefetch, @NonNull Publisher... sources) { return fromArray(sources).concatMapEagerDelayError((Function)Functions.identity(), true, maxConcurrency, prefetch); } @@ -1556,14 +1599,15 @@ public static Flowable concatArrayEagerDelayError(int maxConcurrency, int * * @param the common element base type * @param sources the {@code Iterable} sequence of {@code Publisher}s - * @return the new {@code Publisher} with the concatenating behavior + * @return the new {@code Flowable} with the concatenating behavior + * @throws NullPointerException if {@code sources} is {@code null} */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concatDelayError(@NonNull Iterable> sources) { + public static <@NonNull T> Flowable concatDelayError(@NonNull Iterable<@NonNull ? extends Publisher> sources) { Objects.requireNonNull(sources, "sources is null"); return fromIterable(sources).concatMapDelayError((Function)Functions.identity()); } @@ -1581,13 +1625,14 @@ public static Flowable concatDelayError(@NonNull Iterable the common element base type * @param sources the {@code Publisher} sequence of {@code Publisher}s - * @return the new {@code Publisher} with the concatenating behavior + * @return the new {@code Flowable} with the concatenating behavior + * @throws NullPointerException if {@code sources} is {@code null} */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable concatDelayError(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable concatDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources) { return concatDelayError(sources, bufferSize(), true); } @@ -1606,21 +1651,94 @@ public static Flowable concatDelayError(@NonNull Publisher Flowable concatDelayError(@NonNull Publisher> sources, int prefetch, boolean tillTheEnd) { + public static <@NonNull T> Flowable concatDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources, int prefetch, boolean tillTheEnd) { return fromPublisher(sources).concatMapDelayError((Function)Functions.identity(), tillTheEnd, prefetch); } + /** + * Concatenates a sequence of {@link Publisher}s eagerly into a single stream of values. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * source {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them + * in order, each one after the previous one completes. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream and the inner {@code Publisher}s are + * expected to support backpressure. Violating this assumption, the operator will + * signal {@link MissingBackpressureException}.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code Publisher}s that need to be eagerly concatenated + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @since 2.0 + */ + @CheckReturnValue + @BackpressureSupport(BackpressureKind.FULL) + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Flowable concatEager(@NonNull Iterable<@NonNull ? extends Publisher> sources) { + return concatEager(sources, bufferSize(), bufferSize()); + } + + /** + * Concatenates a sequence of {@link Publisher}s eagerly into a single stream of values and + * runs a limited number of inner sequences at once. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * source {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them + * in order, each one after the previous one completes. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream and both the outer and inner {@code Publisher}s are + * expected to support backpressure. Violating this assumption, the operator will + * signal {@link MissingBackpressureException}.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code Publisher}s that need to be eagerly concatenated + * @param maxConcurrency the maximum number of concurrently running inner {@code Publisher}s; {@link Integer#MAX_VALUE} + * is interpreted as all inner {@code Publisher}s can be active at the same time + * @param prefetch the number of elements to prefetch from each inner {@code Publisher} source + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code prefetch} is non-positive + * @since 2.0 + */ + @CheckReturnValue + @NonNull + @BackpressureSupport(BackpressureKind.FULL) + @SchedulerSupport(SchedulerSupport.NONE) + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static <@NonNull T> Flowable concatEager(@NonNull Iterable<@NonNull ? extends Publisher> sources, int maxConcurrency, int prefetch) { + Objects.requireNonNull(sources, "sources is null"); + ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); + ObjectHelper.verifyPositive(prefetch, "prefetch"); + return RxJavaPlugins.onAssembly(new FlowableConcatMapEager(new FlowableFromIterable(sources), Functions.identity(), maxConcurrency, prefetch, ErrorMode.BOUNDARY)); + } + /** * Concatenates a {@link Publisher} sequence of {@code Publisher}s eagerly into a single stream of values. *

+ * + *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the * emitted source {@code Publisher}s as they are observed. The operator buffers the values emitted by these * {@code Publisher}s and then drains them in order, each one after the previous one completes. @@ -1634,19 +1752,23 @@ public static Flowable concatDelayError(@NonNull Publisher * @param the value type * @param sources a sequence of {@code Publisher}s that need to be eagerly concatenated - * @return the new {@code Publisher} instance with the specified concatenation behavior + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.0 */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable concatEager(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable concatEager(@NonNull Publisher<@NonNull ? extends Publisher> sources) { return concatEager(sources, bufferSize(), bufferSize()); } /** - * Concatenates a {@link Publisher} sequence of {@code Publisher}s eagerly into a single stream of values. + * Concatenates a {@link Publisher} sequence of {@code Publisher}s eagerly into a single stream of values and + * runs a limited number of inner sequences at once. + *

+ * *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the * emitted source {@code Publisher}s as they are observed. The operator buffers the values emitted by these @@ -1664,7 +1786,9 @@ public static Flowable concatEager(@NonNull Publisher Flowable concatEager(@NonNull Publisher Flowable concatEager(@NonNull Publisher> sources, int maxConcurrency, int prefetch) { + public static <@NonNull T> Flowable concatEager(@NonNull Publisher<@NonNull ? extends Publisher> sources, int maxConcurrency, int prefetch) { Objects.requireNonNull(sources, "sources is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); ObjectHelper.verifyPositive(prefetch, "prefetch"); @@ -1680,7 +1804,10 @@ public static Flowable concatEager(@NonNull Publisher + * *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the * source {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them @@ -1695,19 +1822,24 @@ public static Flowable concatEager(@NonNull Publisher * @param the value type * @param sources a sequence of {@code Publisher}s that need to be eagerly concatenated - * @return the new {@code Publisher} instance with the specified concatenation behavior - * @since 2.0 + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable concatEager(@NonNull Iterable> sources) { - return concatEager(sources, bufferSize(), bufferSize()); + public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Iterable<@NonNull ? extends Publisher> sources) { + return concatEagerDelayError(sources, bufferSize(), bufferSize()); } /** - * Concatenates a sequence of {@link Publisher}s eagerly into a single stream of values. + * Concatenates a sequence of {@link Publisher}s eagerly into a single stream of values, + * delaying errors until all the inner sequences terminate and runs a limited number + * of inner sequences at once. + *

+ * *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the * source {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them @@ -1725,19 +1857,92 @@ public static Flowable concatEager(@NonNull Iterable Flowable concatEagerDelayError(@NonNull Iterable<@NonNull ? extends Publisher> sources, int maxConcurrency, int prefetch) { + Objects.requireNonNull(sources, "sources is null"); + ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); + ObjectHelper.verifyPositive(prefetch, "prefetch"); + return RxJavaPlugins.onAssembly(new FlowableConcatMapEager(new FlowableFromIterable(sources), Functions.identity(), maxConcurrency, prefetch, ErrorMode.END)); + } + + /** + * Concatenates a {@link Publisher} sequence of {@code Publisher}s eagerly into a single stream of values, + * delaying errors until all the inner and the outer sequences terminate. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * emitted source {@code Publisher}s as they are observed. The operator buffers the values emitted by these + * {@code Publisher}s and then drains them in order, each one after the previous one completes. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream and both the outer and inner {@code Publisher}s are + * expected to support backpressure. Violating this assumption, the operator will + * signal {@link MissingBackpressureException}.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code Publisher}s that need to be eagerly concatenated + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @BackpressureSupport(BackpressureKind.FULL) + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources) { + return concatEagerDelayError(sources, bufferSize(), bufferSize()); + } + + /** + * Concatenates a {@link Publisher} sequence of {@code Publisher}s eagerly into a single stream of values, + * delaying errors until all the inner and outer sequences terminate and runs a limited number of inner + * sequences at once. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * emitted source {@code Publisher}s as they are observed. The operator buffers the values emitted by these + * {@code Publisher}s and then drains them in order, each one after the previous one completes. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream and both the outer and inner {@code Publisher}s are + * expected to support backpressure. Violating this assumption, the operator will + * signal {@link MissingBackpressureException}.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code Publisher}s that need to be eagerly concatenated + * @param maxConcurrency the maximum number of concurrently running inner {@code Publisher}s; {@link Integer#MAX_VALUE} + * is interpreted as all inner {@code Publisher}s can be active at the same time + * @param prefetch the number of elements to prefetch from each inner {@code Publisher} source + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code prefetch} is non-positive + * @since 3.0.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @SuppressWarnings({ "rawtypes", "unchecked" }) - public static Flowable concatEager(@NonNull Iterable> sources, int maxConcurrency, int prefetch) { + public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources, int maxConcurrency, int prefetch) { Objects.requireNonNull(sources, "sources is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new FlowableConcatMapEager(new FlowableFromIterable(sources), Functions.identity(), maxConcurrency, prefetch, ErrorMode.IMMEDIATE)); + return RxJavaPlugins.onAssembly(new FlowableConcatMapEagerPublisher(sources, Functions.identity(), maxConcurrency, prefetch, ErrorMode.END)); } /** @@ -1789,6 +1994,7 @@ public static Flowable concatEager(@NonNull Iterable Flowable concatEager(@NonNull Iterable Flowable create(@NonNull FlowableOnSubscribe source, @NonNull BackpressureStrategy mode) { + public static <@NonNull T> Flowable create(@NonNull FlowableOnSubscribe source, @NonNull BackpressureStrategy mode) { Objects.requireNonNull(source, "source is null"); Objects.requireNonNull(mode, "mode is null"); return RxJavaPlugins.onAssembly(new FlowableCreate<>(source, mode)); @@ -1808,7 +2014,7 @@ public static Flowable create(@NonNull FlowableOnSubscribe source, @No * that subscribes. That is, for each subscriber, the actual {@code Publisher} that subscriber observes is * determined by the factory function. *

- * + * *

* The defer {@code Subscriber} allows you to defer or delay emitting items from a {@code Publisher} until such time as a * {@code Subscriber} subscribes to the {@code Publisher}. This allows a {@code Subscriber} to easily obtain updates or a @@ -1823,18 +2029,18 @@ public static Flowable create(@NonNull FlowableOnSubscribe source, @No * * @param supplier * the {@code Publisher} factory function to invoke for each {@code Subscriber} that subscribes to the - * resulting {@code Publisher} + * resulting {@code Flowable} * @param * the type of the items emitted by the {@code Publisher} - * @return a {@code Flowable} whose {@code Subscriber}s' subscriptions trigger an invocation of the given - * {@code Publisher} factory function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code supplier} is {@code null} * @see ReactiveX operators documentation: Defer */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable defer(@NonNull Supplier> supplier) { + public static <@NonNull T> Flowable defer(@NonNull Supplier> supplier) { Objects.requireNonNull(supplier, "supplier is null"); return RxJavaPlugins.onAssembly(new FlowableDefer<>(supplier)); } @@ -1843,7 +2049,7 @@ public static Flowable defer(@NonNull Supplier - * + * *

*
Backpressure:
*
This source doesn't produce any elements and effectively ignores downstream backpressure.
@@ -1853,8 +2059,7 @@ public static Flowable defer(@NonNull Supplier * the type of the items (ostensibly) emitted by the {@link Publisher} - * @return a {@code Flowable} that emits no items to the {@code Subscriber} but immediately invokes the - * {@code Subscriber}'s {@link Subscriber#onComplete() onComplete} method + * @return the shared {@code Flowable} instance * @see ReactiveX operators documentation: Empty */ @CheckReturnValue @@ -1862,7 +2067,7 @@ public static Flowable defer(@NonNull Supplier Flowable empty() { + public static <@NonNull T> Flowable empty() { return RxJavaPlugins.onAssembly((Flowable) FlowableEmpty.INSTANCE); } @@ -1870,7 +2075,7 @@ public static Flowable empty() { * Returns a {@code Flowable} that invokes a {@link Subscriber}'s {@link Subscriber#onError onError} method when the * {@code Subscriber} subscribes to it. *

- * + * *

*
Backpressure:
*
This source doesn't produce any elements and effectively ignores downstream backpressure.
@@ -1881,16 +2086,16 @@ public static Flowable empty() { * @param supplier * a {@link Supplier} factory to return a {@link Throwable} for each individual {@code Subscriber} * @param - * the type of the items (ostensibly) emitted by the {@link Publisher} - * @return a {@code Flowable} that invokes the {@code Subscriber}'s {@link Subscriber#onError onError} method when - * the {@code Subscriber} subscribes to it + * the type of the items (ostensibly) emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code supplier} is {@code null} * @see ReactiveX operators documentation: Throw */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable error(@NonNull Supplier supplier) { + public static <@NonNull T> Flowable error(@NonNull Supplier supplier) { Objects.requireNonNull(supplier, "supplier is null"); return RxJavaPlugins.onAssembly(new FlowableError<>(supplier)); } @@ -1899,7 +2104,7 @@ public static Flowable error(@NonNull Supplier suppl * Returns a {@code Flowable} that invokes a {@link Subscriber}'s {@link Subscriber#onError onError} method when the * {@code Subscriber} subscribes to it. *

- * + * *

*
Backpressure:
*
This source doesn't produce any elements and effectively ignores downstream backpressure.
@@ -1910,24 +2115,57 @@ public static Flowable error(@NonNull Supplier suppl * @param throwable * the particular {@link Throwable} to pass to {@link Subscriber#onError onError} * @param - * the type of the items (ostensibly) emitted by the {@link Publisher} - * @return a {@code Flowable} that invokes the {@code Subscriber}'s {@link Subscriber#onError onError} method when - * the {@code Subscriber} subscribes to it + * the type of the items (ostensibly) emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code throwable} is {@code null} * @see ReactiveX operators documentation: Throw */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable error(@NonNull Throwable throwable) { + public static <@NonNull T> Flowable error(@NonNull Throwable throwable) { Objects.requireNonNull(throwable, "throwable is null"); return error(Functions.justSupplier(throwable)); } /** - * Converts an Array into a {@link Publisher} that emits the items in the Array. + * Returns a {@code Flowable} instance that runs the given {@link Action} for each {@link Subscriber} and + * emits either its exception or simply completes. *

- * + * + *

+ *
Backpressure:
+ *
This source doesn't produce any elements and effectively ignores downstream backpressure.
+ *
Scheduler:
+ *
{@code fromAction} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If the {@code Action} throws an exception, the respective {@link Throwable} is + * delivered to the downstream via {@link Subscriber#onError(Throwable)}, + * except when the downstream has canceled the resulting {@code Flowable} source. + * In this latter case, the {@code Throwable} is delivered to the global error handler via + * {@link RxJavaPlugins#onError(Throwable)} as an {@link io.reactivex.rxjava3.exceptions.UndeliverableException UndeliverableException}. + *
+ *
+ * @param the target type + * @param action the {@code Action} to run for each {@code Subscriber} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code action} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.PASS_THROUGH) + public static <@NonNull T> Flowable fromAction(@NonNull Action action) { + Objects.requireNonNull(action, "action is null"); + return RxJavaPlugins.onAssembly(new FlowableFromAction<>(action)); + } + + /** + * Converts an array into a {@link Publisher} that emits the items in the array. + *

+ * *

*
Backpressure:
*
The operator honors backpressure from downstream and iterates the given {@code array} @@ -1939,8 +2177,9 @@ public static Flowable error(@NonNull Throwable throwable) { * @param items * the array of elements * @param - * the type of items in the Array and the type of items to be emitted by the resulting {@code Publisher} - * @return a {@code Flowable} that emits each item in the source Array + * the type of items in the array and the type of items to be emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code items} is {@code null} * @see ReactiveX operators documentation: From */ @CheckReturnValue @@ -1963,7 +2202,7 @@ public static Flowable error(@NonNull Throwable throwable) { * Returns a {@code Flowable} that, when a {@link Subscriber} subscribes to it, invokes a function you specify and then * emits the value returned from that function. *

- * + * *

* This allows you to defer the execution of the function you specify until a {@code Subscriber} subscribes to the * {@link Publisher}. That is to say, it makes the function "lazy." @@ -1981,12 +2220,13 @@ public static Flowable error(@NonNull Throwable throwable) { *

*
* - * @param supplier + * @param callable * a function, the execution of which should be deferred; {@code fromCallable} will invoke this * function only when a {@code Subscriber} subscribes to the {@code Publisher} that {@code fromCallable} returns * @param * the type of the item emitted by the {@code Publisher} - * @return a {@code Flowable} whose {@code Subscriber}s' subscriptions trigger an invocation of the given function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code callable} is {@code null} * @see #defer(Supplier) * @see #fromSupplier(Supplier) * @since 2.0 @@ -1995,21 +2235,44 @@ public static Flowable error(@NonNull Throwable throwable) { @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static <@NonNull T> Flowable fromCallable(@NonNull Callable supplier) { - Objects.requireNonNull(supplier, "supplier is null"); - return RxJavaPlugins.onAssembly(new FlowableFromCallable<>(supplier)); + public static <@NonNull T> Flowable fromCallable(@NonNull Callable callable) { + Objects.requireNonNull(callable, "callable is null"); + return RxJavaPlugins.onAssembly(new FlowableFromCallable<>(callable)); } /** - * Converts a {@link Future} into a {@link Publisher}. + * Wraps a {@link CompletableSource} into a {@code Flowable}. *

- * + * + *

+ *
Backpressure:
+ *
This source doesn't produce any elements and effectively ignores downstream backpressure.
+ *
Scheduler:
+ *
{@code fromCompletable} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the target type + * @param completableSource the {@code CompletableSource} to convert from + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code completableSource} is {@code null} + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.PASS_THROUGH) + public static <@NonNull T> Flowable fromCompletable(@NonNull CompletableSource completableSource) { + Objects.requireNonNull(completableSource, "completableSource is null"); + return RxJavaPlugins.onAssembly(new FlowableFromCompletable<>(completableSource)); + } + + /** + * Converts a {@link Future} into a {@link Publisher}. *

- * You can convert any object that supports the {@code Future} interface into a {@code Publisher} that emits the - * return value of the {@link Future#get} method of that object by passing the object into the {@code from} - * method. + * *

- * Important note: This {@code Publisher} is blocking on the thread it gets subscribed on; you cannot cancel it. + * The operator calls {@link Future#get()}, which is a blocking method, on the subscription thread. + * It is recommended applying {@link #subscribeOn(Scheduler)} to move this blocking wait to a + * background thread, and if the {@link Scheduler} supports it, interrupt the wait when the flow + * is disposed. *

* Also note that this operator will consume a {@link CompletionStage}-based {@code Future} subclass (such as * {@link CompletableFuture}) in a blocking manner as well. Use the {@link #fromCompletionStage(CompletionStage)} @@ -2021,15 +2284,16 @@ public static Flowable error(@NonNull Throwable throwable) { *

Backpressure:
*
The operator honors backpressure from downstream.
*
Scheduler:
- *
{@code fromFuture} does not operate by default on a particular {@link Scheduler}.
+ *
{@code fromFuture} does not operate by default on a particular {@code Scheduler}.
*
* * @param future * the source {@code Future} * @param * the type of object that the {@code Future} returns, and also the type of item to be emitted by - * the resulting {@code Publisher} - * @return a {@code Flowable} that emits the item from the source {@code Future} + * the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code future} is {@code null} * @see ReactiveX operators documentation: From * @see #fromCompletionStage(CompletionStage) */ @@ -2045,17 +2309,16 @@ public static Flowable error(@NonNull Throwable throwable) { /** * Converts a {@link Future} into a {@link Publisher}, with a timeout on the {@code Future}. *

- * + * *

- * You can convert any object that supports the {@code Future} interface into a {@code Publisher} that emits the - * return value of the {@link Future#get} method of that object by passing the object into the {@code fromFuture} - * method. + * The operator calls {@link Future#get(long, TimeUnit)}, which is a blocking method, on the subscription thread. + * It is recommended applying {@link #subscribeOn(Scheduler)} to move this blocking wait to a + * background thread, and if the {@link Scheduler} supports it, interrupt the wait when the flow + * is disposed. *

* Unlike 1.x, canceling the {@code Flowable} won't cancel the future. If necessary, one can use composition to achieve the * cancellation effect: {@code futurePublisher.doOnCancel(() -> future.cancel(true));}. *

- * Important note: This {@code Publisher} is blocking on the thread it gets subscribed on; you cannot cancel it. - *

* Also note that this operator will consume a {@link CompletionStage}-based {@code Future} subclass (such as * {@link CompletableFuture}) in a blocking manner as well. Use the {@link #fromCompletionStage(CompletionStage)} * operator to convert and consume such sources in a non-blocking fashion instead. @@ -2063,7 +2326,7 @@ public static Flowable error(@NonNull Throwable throwable) { *

Backpressure:
*
The operator honors backpressure from downstream.
*
Scheduler:
- *
{@code fromFuture} does not operate by default on a particular {@link Scheduler}.
+ *
{@code fromFuture} does not operate by default on a particular {@code Scheduler}.
*
* * @param future @@ -2074,8 +2337,9 @@ public static Flowable error(@NonNull Throwable throwable) { * the {@link TimeUnit} of the {@code timeout} argument * @param * the type of object that the {@code Future} returns, and also the type of item to be emitted by - * the resulting {@code Publisher} - * @return a {@code Flowable} that emits the item from the source {@code Future} + * the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code future} or {@code unit} is {@code null} * @see ReactiveX operators documentation: From * @see #fromCompletionStage(CompletionStage) */ @@ -2090,170 +2354,235 @@ public static Flowable error(@NonNull Throwable throwable) { } /** - * Converts a {@link Future} into a {@link Publisher}, with a timeout on the {@code Future}. - *

- * - *

- * You can convert any object that supports the {@code Future} interface into a {@code Publisher} that emits the - * return value of the {@link Future#get} method of that object by passing the object into the {@code from} - * method. - *

- * Unlike 1.x, canceling the {@code Flowable} won't cancel the future. If necessary, one can use composition to achieve the - * cancellation effect: {@code futurePublisher.doOnCancel(() -> future.cancel(true));}. - *

- * Important note: This {@code Publisher} is blocking; you cannot cancel it. + * Converts an {@link Iterable} sequence into a {@link Publisher} that emits the items in the sequence. *

- * Also note that this operator will consume a {@link CompletionStage}-based {@code Future} subclass (such as - * {@link CompletableFuture}) in a blocking manner as well. Use the {@link #fromCompletionStage(CompletionStage)} - * operator to convert and consume such sources in a non-blocking fashion instead. + * *

*
Backpressure:
- *
The operator honors backpressure from downstream.
+ *
The operator honors backpressure from downstream and iterates the given {@code iterable} + * on demand (i.e., when requested).
*
Scheduler:
- *
{@code fromFuture} does not operate by default on a particular {@link Scheduler}.
+ *
{@code fromIterable} does not operate by default on a particular {@link Scheduler}.
*
* - * @param future - * the source {@code Future} - * @param timeout - * the maximum time to wait before calling {@code get} - * @param unit - * the {@link TimeUnit} of the {@code timeout} argument - * @param scheduler - * the {@code Scheduler} to wait for the {@code Future} on. Use a {@code Scheduler} such as - * {@link Schedulers#io()} that can block and wait on the {@code Future} + * @param source + * the source {@code Iterable} sequence * @param - * the type of object that the {@code Future} returns, and also the type of item to be emitted by - * the resulting {@code Publisher} - * @return a {@code Flowable} that emits the item from the source {@code Future} + * the type of items in the {@code Iterable} sequence and the type of items to be emitted by the + * resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source} is {@code null} * @see ReactiveX operators documentation: From - * @see #fromCompletionStage(CompletionStage) + * @see #fromStream(Stream) */ - @SuppressWarnings({ "unchecked" }) @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.CUSTOM) - public static <@NonNull T> Flowable fromFuture(Future future, long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - Objects.requireNonNull(scheduler, "scheduler is null"); - return fromFuture((Future)future, timeout, unit).subscribeOn(scheduler); + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Flowable fromIterable(@NonNull Iterable source) { + Objects.requireNonNull(source, "source is null"); + return RxJavaPlugins.onAssembly(new FlowableFromIterable<>(source)); } /** - * Converts a {@link Future}, operating on a specified {@link Scheduler}, into a {@link Publisher}. - *

- * - *

- * You can convert any object that supports the {@code Future} interface into a {@code Publisher} that emits the - * return value of the {@link Future#get} method of that object by passing the object into the {@code from} - * method. + * Returns a {@code Flowable} instance that when subscribed to, subscribes to the {@link MaybeSource} instance and + * emits {@code onSuccess} as a single item or forwards any {@code onComplete} or + * {@code onError} signal. *

- * Unlike 1.x, canceling the {@code Flowable} won't cancel the future. If necessary, one can use composition to achieve the - * cancellation effect: {@code futurePublisher.doOnCancel(() -> future.cancel(true));}. + * *

*
Backpressure:
*
The operator honors backpressure from downstream.
*
Scheduler:
- *
You specify which {@code Scheduler} this operator will use.
+ *
{@code fromMaybe} does not operate by default on a particular {@link Scheduler}.
*
- * - * @param future - * the source {@code Future} - * @param scheduler - * the {@code Scheduler} to wait for the {@code Future} on. Use a {@code Scheduler} such as - * {@link Schedulers#io()} that can block and wait on the {@code Future} - * @param - * the type of object that the {@code Future} returns, and also the type of item to be emitted by - * the resulting {@code Publisher} - * @return a {@code Flowable} that emits the item from the source {@code Future} - * @see ReactiveX operators documentation: From + * @param the value type of the {@code MaybeSource} element + * @param maybe the {@code MaybeSource} instance to subscribe to, not {@code null} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code maybe} is {@code null} + * @since 3.0.0 */ - @SuppressWarnings({ "unchecked" }) @CheckReturnValue @NonNull + @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.CUSTOM) - public static <@NonNull T> Flowable fromFuture(Future future, @NonNull Scheduler scheduler) { - Objects.requireNonNull(scheduler, "scheduler is null"); - return fromFuture((Future)future).subscribeOn(scheduler); + public static <@NonNull T> Flowable fromMaybe(@NonNull MaybeSource maybe) { + Objects.requireNonNull(maybe, "maybe is null"); + return RxJavaPlugins.onAssembly(new MaybeToFlowable<>(maybe)); } /** - * Converts an {@link Iterable} sequence into a {@link Publisher} that emits the items in the sequence. + * Converts the given {@link ObservableSource} into a {@code Flowable} by applying the specified backpressure strategy. + *

+ * Marble diagrams for the various backpressure strategies are as follows: + *

    + *
  • {@link BackpressureStrategy#BUFFER} + *

    + * + *

  • + *
  • {@link BackpressureStrategy#DROP} + *

    + * + *

  • + *
  • {@link BackpressureStrategy#LATEST} + *

    + * + *

  • + *
  • {@link BackpressureStrategy#ERROR} *

    - * + * + *

  • + *
  • {@link BackpressureStrategy#MISSING} + *

    + * + *

  • + *
*
*
Backpressure:
- *
The operator honors backpressure from downstream and iterates the given {@code iterable} - * on demand (i.e., when requested).
+ *
The operator applies the chosen backpressure strategy of {@link BackpressureStrategy} enum.
*
Scheduler:
- *
{@code fromIterable} does not operate by default on a particular {@link Scheduler}.
+ *
{@code fromObservable} does not operate by default on a particular {@link Scheduler}.
*
* - * @param source - * the source {@code Iterable} sequence - * @param - * the type of items in the {@code Iterable} sequence and the type of items to be emitted by the - * resulting {@code Publisher} - * @return a {@code Flowable} that emits each item in the source {@code Iterable} sequence - * @see ReactiveX operators documentation: From - * @see #fromStream(Stream) + * @param the element type of the source and resulting sequence + * @param source the {@code ObservableSource} to convert + * @param strategy the backpressure strategy to apply + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source} or {@code strategy} is {@code null} + */ + @BackpressureSupport(BackpressureKind.SPECIAL) + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Flowable fromObservable(@NonNull ObservableSource source, @NonNull BackpressureStrategy strategy) { + Objects.requireNonNull(source, "source is null"); + Objects.requireNonNull(strategy, "strategy is null"); + Flowable f = new FlowableFromObservable<>(source); + switch (strategy) { + case DROP: + return f.onBackpressureDrop(); + case LATEST: + return f.onBackpressureLatest(); + case MISSING: + return f; + case ERROR: + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureError<>(f)); + default: + return f.onBackpressureBuffer(); + } + } + + /** + * Converts an arbitrary Reactive Streams {@link Publisher} into a {@code Flowable} if not already a + * {@code Flowable}. + *

+ * The {@code Publisher} must follow the + * Reactive-Streams specification. + * Violating the specification may result in undefined behavior. + *

+ * If possible, use {@link #create(FlowableOnSubscribe, BackpressureStrategy)} to create a + * source-like {@code Flowable} instead. + *

+ * Note that even though {@code Publisher} appears to be a functional interface, it + * is not recommended to implement it through a lambda as the specification requires + * state management that is not achievable with a stateless lambda. + *

+ *
Backpressure:
+ *
The operator is a pass-through for backpressure and its behavior is determined by the + * backpressure behavior of the wrapped publisher.
+ *
Scheduler:
+ *
{@code fromPublisher} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type of the flow + * @param publisher the {@code Publisher} to convert + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code publisher} is {@code null} + * @see #create(FlowableOnSubscribe, BackpressureStrategy) + */ + @CheckReturnValue + @NonNull + @BackpressureSupport(BackpressureKind.PASS_THROUGH) + @SchedulerSupport(SchedulerSupport.NONE) + @SuppressWarnings("unchecked") + public static <@NonNull T> Flowable fromPublisher(@NonNull Publisher publisher) { + if (publisher instanceof Flowable) { + return RxJavaPlugins.onAssembly((Flowable)publisher); + } + Objects.requireNonNull(publisher, "publisher is null"); + + return RxJavaPlugins.onAssembly(new FlowableFromPublisher<>(publisher)); + } + + /** + * Returns a {@code Flowable} instance that runs the given {@link Runnable} for each {@link Subscriber} and + * emits either its unchecked exception or simply completes. + *

+ * + *

+ * If the code to be wrapped needs to throw a checked or more broader {@link Throwable} exception, that + * exception has to be converted to an unchecked exception by the wrapped code itself. Alternatively, + * use the {@link #fromAction(Action)} method which allows the wrapped code to throw any {@code Throwable} + * exception and will signal it to observers as-is. + *

+ *
Backpressure:
+ *
This source doesn't produce any elements and effectively ignores downstream backpressure.
+ *
Scheduler:
+ *
{@code fromRunnable} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If the {@code Runnable} throws an exception, the respective {@code Throwable} is + * delivered to the downstream via {@link Subscriber#onError(Throwable)}, + * except when the downstream has canceled the resulting {@code Flowable} source. + * In this latter case, the {@code Throwable} is delivered to the global error handler via + * {@link RxJavaPlugins#onError(Throwable)} as an {@link io.reactivex.rxjava3.exceptions.UndeliverableException UndeliverableException}. + *
+ *
+ * @param the target type + * @param run the {@code Runnable} to run for each {@code Subscriber} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code run} is {@code null} + * @since 3.0.0 + * @see #fromAction(Action) */ @CheckReturnValue @NonNull - @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static <@NonNull T> Flowable fromIterable(@NonNull Iterable source) { - Objects.requireNonNull(source, "source is null"); - return RxJavaPlugins.onAssembly(new FlowableFromIterable<>(source)); + @BackpressureSupport(BackpressureKind.PASS_THROUGH) + public static <@NonNull T> Flowable fromRunnable(@NonNull Runnable run) { + Objects.requireNonNull(run, "run is null"); + return RxJavaPlugins.onAssembly(new FlowableFromRunnable<>(run)); } /** - * Converts an arbitrary Reactive Streams {@link Publisher} into a {@code Flowable} if not already a - * {@code Flowable}. - *

- * The {@code Publisher} must follow the - * Reactive-Streams specification. - * Violating the specification may result in undefined behavior. - *

- * If possible, use {@link #create(FlowableOnSubscribe, BackpressureStrategy)} to create a - * source-like {@code Flowable} instead. + * Returns a {@code Flowable} instance that when subscribed to, subscribes to the {@link SingleSource} instance and + * emits {@code onSuccess} as a single item or forwards the {@code onError} signal. *

- * Note that even though {@code Publisher} appears to be a functional interface, it - * is not recommended to implement it through a lambda as the specification requires - * state management that is not achievable with a stateless lambda. + * *

*
Backpressure:
- *
The operator is a pass-through for backpressure and its behavior is determined by the - * backpressure behavior of the wrapped publisher.
+ *
The operator honors backpressure from downstream.
*
Scheduler:
- *
{@code fromPublisher} does not operate by default on a particular {@link Scheduler}.
+ *
{@code fromSingle} does not operate by default on a particular {@link Scheduler}.
*
- * @param the value type of the flow - * @param source the {@code Publisher} to convert + * @param the value type of the {@code SingleSource} element + * @param source the {@code SingleSource} instance to subscribe to, not {@code null} * @return the new {@code Flowable} instance - * @throws NullPointerException if the {@code source} {@code Publisher} is {@code null} - * @see #create(FlowableOnSubscribe, BackpressureStrategy) + * @throws NullPointerException if {@code source} is {@code null} + * @since 3.0.0 */ @CheckReturnValue @NonNull - @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - @SuppressWarnings("unchecked") - public static Flowable fromPublisher(@NonNull Publisher source) { - if (source instanceof Flowable) { - return RxJavaPlugins.onAssembly((Flowable)source); - } + @BackpressureSupport(BackpressureKind.FULL) + public static <@NonNull T> Flowable fromSingle(@NonNull SingleSource source) { Objects.requireNonNull(source, "source is null"); - - return RxJavaPlugins.onAssembly(new FlowableFromPublisher<>(source)); + return RxJavaPlugins.onAssembly(new SingleToFlowable<>(source)); } /** * Returns a {@code Flowable} that, when a {@link Subscriber} subscribes to it, invokes a supplier function you specify and then * emits the value returned from that function. *

- * + * *

* This allows you to defer the execution of the function you specify until a {@code Subscriber} subscribes to the * {@link Publisher}. That is to say, it makes the function "lazy." @@ -2276,7 +2605,8 @@ public static Flowable fromPublisher(@NonNull Publisher sour * function only when a {@code Subscriber} subscribes to the {@code Publisher} that {@code fromSupplier} returns * @param * the type of the item emitted by the {@code Publisher} - * @return a {@code Flowable} whose {@code Subscriber}s' subscriptions trigger an invocation of the given function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code supplier} is {@code null} * @see #defer(Supplier) * @see #fromCallable(Callable) * @since 3.0.0 @@ -2310,12 +2640,13 @@ public static Flowable fromPublisher(@NonNull Publisher sour * {@code onComplete} to signal a value or a terminal event. Signaling multiple {@code onNext} * in a call will make the operator signal {@link IllegalStateException}. * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code generator} is {@code null} */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable generate(@NonNull Consumer<@NonNull Emitter> generator) { + public static <@NonNull T> Flowable generate(@NonNull Consumer<@NonNull Emitter> generator) { Objects.requireNonNull(generator, "generator is null"); return generate(Functions.nullSupplier(), FlowableInternalHelper.simpleGenerator(generator), @@ -2344,12 +2675,13 @@ public static Flowable generate(@NonNull Consumer<@NonNull Emitter> ge * {@code onComplete} to signal a value or a terminal event. Signaling multiple {@code onNext} * in a call will make the operator signal {@link IllegalStateException}. * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code initialState} or {@code generator} is {@code null} */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable generate(@NonNull Supplier initialState, @NonNull BiConsumer> generator) { + public static <@NonNull T, @NonNull S> Flowable generate(@NonNull Supplier initialState, @NonNull BiConsumer> generator) { Objects.requireNonNull(generator, "generator is null"); return generate(initialState, FlowableInternalHelper.simpleBiGenerator(generator), Functions.emptyConsumer()); @@ -2379,12 +2711,13 @@ public static Flowable generate(@NonNull Supplier initialState, @No * @param disposeState the {@code Consumer} that is called with the current state when the generator * terminates the sequence or it gets canceled * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code initialState}, {@code generator} or {@code disposeState} is {@code null} */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable generate(@NonNull Supplier initialState, @NonNull BiConsumer> generator, + public static <@NonNull T, @NonNull S> Flowable generate(@NonNull Supplier initialState, @NonNull BiConsumer> generator, @NonNull Consumer disposeState) { Objects.requireNonNull(generator, "generator is null"); return generate(initialState, FlowableInternalHelper.simpleBiGenerator(generator), disposeState); @@ -2413,12 +2746,13 @@ public static Flowable generate(@NonNull Supplier initialState, @No * the next invocation. Signaling multiple {@code onNext} * in a call will make the operator signal {@link IllegalStateException}. * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code initialState} or {@code generator} is {@code null} */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable generate(@NonNull Supplier initialState, @NonNull BiFunction, S> generator) { + public static <@NonNull T, @NonNull S> Flowable generate(@NonNull Supplier initialState, @NonNull BiFunction, S> generator) { return generate(initialState, generator, Functions.emptyConsumer()); } @@ -2447,12 +2781,13 @@ public static Flowable generate(@NonNull Supplier initialState, @No * @param disposeState the {@link Consumer} that is called with the current state when the generator * terminates the sequence or it gets canceled * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code initialState}, {@code generator} or {@code disposeState} is {@code null} */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable generate(@NonNull Supplier initialState, @NonNull BiFunction, S> generator, @NonNull Consumer disposeState) { + public static <@NonNull T, @NonNull S> Flowable generate(@NonNull Supplier initialState, @NonNull BiFunction, S> generator, @NonNull Consumer disposeState) { Objects.requireNonNull(initialState, "initialState is null"); Objects.requireNonNull(generator, "generator is null"); Objects.requireNonNull(disposeState, "disposeState is null"); @@ -2463,7 +2798,7 @@ public static Flowable generate(@NonNull Supplier initialState, @No * Returns a {@code Flowable} that emits a {@code 0L} after the {@code initialDelay} and ever-increasing numbers * after each {@code period} of time thereafter. *

- * + * *

*
Backpressure:
*
The operator generates values based on time and ignores downstream backpressure which @@ -2479,8 +2814,8 @@ public static Flowable generate(@NonNull Supplier initialState, @No * the period of time between emissions of the subsequent numbers * @param unit * the time unit for both {@code initialDelay} and {@code period} - * @return a {@code Flowable} that emits a 0L after the {@code initialDelay} and ever-increasing numbers after - * each {@code period} of time thereafter + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Interval * @since 1.0.12 */ @@ -2496,7 +2831,7 @@ public static Flowable interval(long initialDelay, long period, @NonNull T * Returns a {@code Flowable} that emits a {@code 0L} after the {@code initialDelay} and ever-increasing numbers * after each {@code period} of time thereafter, on a specified {@link Scheduler}. *

- * + * *

*
Backpressure:
*
The operator generates values based on time and ignores downstream backpressure which @@ -2514,8 +2849,8 @@ public static Flowable interval(long initialDelay, long period, @NonNull T * the time unit for both {@code initialDelay} and {@code period} * @param scheduler * the {@code Scheduler} on which the waiting happens and items are emitted - * @return a {@code Flowable} that emits a 0L after the {@code initialDelay} and ever-increasing numbers after - * each {@code period} of time thereafter, while running on the given {@code Scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Interval * @since 1.0.12 */ @@ -2532,7 +2867,7 @@ public static Flowable interval(long initialDelay, long period, @NonNull T /** * Returns a {@code Flowable} that emits a sequential number every specified interval of time. *

- * + * *

*
Backpressure:
*
The operator signals a {@link MissingBackpressureException} if the downstream @@ -2545,7 +2880,8 @@ public static Flowable interval(long initialDelay, long period, @NonNull T * the period size in time units (see below) * @param unit * time units to use for the interval size - * @return a {@code Flowable} that emits a sequential number each time interval + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Interval */ @CheckReturnValue @@ -2560,7 +2896,7 @@ public static Flowable interval(long period, @NonNull TimeUnit unit) { * Returns a {@code Flowable} that emits a sequential number every specified interval of time, on a * specified {@link Scheduler}. *

- * + * *

*
Backpressure:
*
The operator generates values based on time and ignores downstream backpressure which @@ -2576,7 +2912,8 @@ public static Flowable interval(long period, @NonNull TimeUnit unit) { * time units to use for the interval size * @param scheduler * the {@code Scheduler} to use for scheduling the items - * @return a {@code Flowable} that emits a sequential number each time interval + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Interval */ @CheckReturnValue @@ -2603,11 +2940,16 @@ public static Flowable interval(long period, @NonNull TimeUnit unit, @NonN * @param period the period between subsequent values * @param unit the unit of measure of the {@code initialDelay} and {@code period} amounts * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException + * if {@code count} is less than zero, or if {@code start} + {@code count} − 1 exceeds + * {@link Long#MAX_VALUE} + * @see #range(int, int) */ @CheckReturnValue + @NonNull @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.COMPUTATION) - @NonNull public static Flowable intervalRange(long start, long count, long initialDelay, long period, @NonNull TimeUnit unit) { return intervalRange(start, count, initialDelay, period, unit, Schedulers.computation()); } @@ -2629,6 +2971,10 @@ public static Flowable intervalRange(long start, long count, long initialD * @param unit the unit of measure of the {@code initialDelay} and {@code period} amounts * @param scheduler the target {@code Scheduler} where the values and terminal signals will be emitted * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException + * if {@code count} is less than zero, or if {@code start} + {@code count} − 1 exceeds + * {@link Long#MAX_VALUE} */ @CheckReturnValue @NonNull @@ -2655,7 +3001,7 @@ public static Flowable intervalRange(long start, long count, long initialD /** * Returns a {@code Flowable} that signals the given (constant reference) item and then completes. *

- * + * *

* Note that the item is taken and re-emitted as is and not computed by any means by {@code just}. Use {@link #fromCallable(Callable)} * to generate a single item on demand (when {@link Subscriber}s subscribe to it). @@ -2675,7 +3021,8 @@ public static Flowable intervalRange(long start, long count, long initialD * the item to emit * @param * the type of that item - * @return a {@code Flowable} that emits {@code value} as a single item and then completes + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code item} is {@code null} * @see ReactiveX operators documentation: Just * @see #just(Object, Object) * @see #fromCallable(Callable) @@ -2694,7 +3041,7 @@ public static Flowable intervalRange(long start, long count, long initialD /** * Converts two items into a {@link Publisher} that emits those items. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream and signals each value on-demand (i.e., when requested).
@@ -2708,7 +3055,8 @@ public static Flowable intervalRange(long start, long count, long initialD * second item * @param * the type of these items - * @return a {@code Flowable} that emits each item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code item1} or {@code item2} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @@ -2725,7 +3073,7 @@ public static Flowable intervalRange(long start, long count, long initialD /** * Converts three items into a {@link Publisher} that emits those items. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream and signals each value on-demand (i.e., when requested).
@@ -2741,7 +3089,8 @@ public static Flowable intervalRange(long start, long count, long initialD * third item * @param * the type of these items - * @return a {@code Flowable} that emits each item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code item1}, {@code item2} or {@code item3} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @@ -2759,7 +3108,7 @@ public static Flowable intervalRange(long start, long count, long initialD /** * Converts four items into a {@link Publisher} that emits those items. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream and signals each value on-demand (i.e., when requested).
@@ -2777,7 +3126,9 @@ public static Flowable intervalRange(long start, long count, long initialD * fourth item * @param * the type of these items - * @return a {@code Flowable} that emits each item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3}, + * or {@code item4} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @@ -2796,7 +3147,7 @@ public static Flowable intervalRange(long start, long count, long initialD /** * Converts five items into a {@link Publisher} that emits those items. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream and signals each value on-demand (i.e., when requested).
@@ -2816,7 +3167,9 @@ public static Flowable intervalRange(long start, long count, long initialD * fifth item * @param * the type of these items - * @return a {@code Flowable} that emits each item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3}, + * {@code item4} or {@code item5} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @@ -2836,7 +3189,7 @@ public static Flowable intervalRange(long start, long count, long initialD /** * Converts six items into a {@link Publisher} that emits those items. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream and signals each value on-demand (i.e., when requested).
@@ -2858,7 +3211,9 @@ public static Flowable intervalRange(long start, long count, long initialD * sixth item * @param * the type of these items - * @return a {@code Flowable} that emits each item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3}, + * {@code item4}, {@code item5} or {@code item6} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @@ -2879,7 +3234,7 @@ public static Flowable intervalRange(long start, long count, long initialD /** * Converts seven items into a {@link Publisher} that emits those items. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream and signals each value on-demand (i.e., when requested).
@@ -2903,7 +3258,10 @@ public static Flowable intervalRange(long start, long count, long initialD * seventh item * @param * the type of these items - * @return a {@code Flowable} that emits each item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3}, + * {@code item4}, {@code item5}, {@code item6} + * or {@code item7} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @@ -2925,7 +3283,7 @@ public static Flowable intervalRange(long start, long count, long initialD /** * Converts eight items into a {@link Publisher} that emits those items. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream and signals each value on-demand (i.e., when requested).
@@ -2951,7 +3309,10 @@ public static Flowable intervalRange(long start, long count, long initialD * eighth item * @param * the type of these items - * @return a {@code Flowable} that emits each item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3}, + * {@code item4}, {@code item5}, {@code item6}, + * {@code item7} or {@code item8} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @@ -2974,7 +3335,7 @@ public static Flowable intervalRange(long start, long count, long initialD /** * Converts nine items into a {@link Publisher} that emits those items. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream and signals each value on-demand (i.e., when requested).
@@ -3002,7 +3363,10 @@ public static Flowable intervalRange(long start, long count, long initialD * ninth item * @param * the type of these items - * @return a {@code Flowable} that emits each item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3}, + * {@code item4}, {@code item5}, {@code item6}, + * {@code item7}, {@code item8} or {@code item9} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @@ -3026,7 +3390,7 @@ public static Flowable intervalRange(long start, long count, long initialD /** * Converts ten items into a {@link Publisher} that emits those items. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream and signals each value on-demand (i.e., when requested).
@@ -3056,7 +3420,11 @@ public static Flowable intervalRange(long start, long count, long initialD * tenth item * @param * the type of these items - * @return a {@code Flowable} that emits each item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3}, + * {@code item4}, {@code item5}, {@code item6}, + * {@code item7}, {@code item8}, {@code item9}, + * or {@code item10} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @@ -3082,7 +3450,7 @@ public static Flowable intervalRange(long start, long count, long initialD * Flattens an {@link Iterable} of {@link Publisher}s into one {@code Publisher}, without any transformation, while limiting the * number of concurrent subscriptions to these {@code Publisher}s. *

- * + * *

* You can combine the items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by * using the {@code merge} method. @@ -3114,10 +3482,10 @@ public static Flowable intervalRange(long start, long count, long initialD * the maximum number of {@code Publisher}s that may be subscribed to concurrently * @param bufferSize * the number of items to prefetch from each inner {@code Publisher} - * @return a {@code Flowable} that emits items that are the result of flattening the items emitted by the - * {@code Publisher}s in the {@code Iterable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @throws IllegalArgumentException - * if {@code maxConcurrency} is less than or equal to 0 + * if {@code maxConcurrency} or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(Iterable, int, int) */ @@ -3126,15 +3494,15 @@ public static Flowable intervalRange(long start, long count, long initialD @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable merge(@NonNull Iterable> sources, int maxConcurrency, int bufferSize) { + public static <@NonNull T> Flowable merge(@NonNull Iterable<@NonNull ? extends Publisher> sources, int maxConcurrency, int bufferSize) { return fromIterable(sources).flatMap((Function)Functions.identity(), false, maxConcurrency, bufferSize); } /** - * Flattens an {@link Iterable} of {@link Publisher}s into one {@code Publisher}, without any transformation, while limiting the + * Flattens an array of {@link Publisher}s into one {@code Publisher}, without any transformation, while limiting the * number of concurrent subscriptions to these {@code Publisher}s. *

- * + * *

* You can combine the items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by * using the {@code merge} method. @@ -3166,10 +3534,10 @@ public static Flowable merge(@NonNull IterableReactiveX operators documentation: Merge * @see #mergeArrayDelayError(int, int, Publisher...) */ @@ -3179,14 +3547,14 @@ public static Flowable merge(@NonNull Iterable Flowable mergeArray(int maxConcurrency, int bufferSize, @NonNull Publisher... sources) { + public static <@NonNull T> Flowable mergeArray(int maxConcurrency, int bufferSize, @NonNull Publisher... sources) { return fromArray(sources).flatMap((Function)Functions.identity(), false, maxConcurrency, bufferSize); } /** * Flattens an {@link Iterable} of {@link Publisher}s into one {@code Publisher}, without any transformation. *

- * + * *

* You can combine the items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by * using the {@code merge} method. @@ -3214,8 +3582,8 @@ public static Flowable mergeArray(int maxConcurrency, int bufferSize, @No * @param the common element base type * @param sources * the {@code Iterable} of {@code Publisher}s - * @return a {@code Flowable} that emits items that are the result of flattening the items emitted by the - * {@code Publisher}s in the {@code Iterable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(Iterable) */ @@ -3224,7 +3592,7 @@ public static Flowable mergeArray(int maxConcurrency, int bufferSize, @No @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable merge(@NonNull Iterable> sources) { + public static <@NonNull T> Flowable merge(@NonNull Iterable<@NonNull ? extends Publisher> sources) { return fromIterable(sources).flatMap((Function)Functions.identity()); } @@ -3232,7 +3600,7 @@ public static Flowable merge(@NonNull Iterable - * + * *

* You can combine the items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by * using the {@code merge} method. @@ -3262,8 +3630,8 @@ public static Flowable merge(@NonNull IterableReactiveX operators documentation: Merge @@ -3274,7 +3642,7 @@ public static Flowable merge(@NonNull Iterable Flowable merge(@NonNull Iterable> sources, int maxConcurrency) { + public static <@NonNull T> Flowable merge(@NonNull Iterable<@NonNull ? extends Publisher> sources, int maxConcurrency) { return fromIterable(sources).flatMap((Function)Functions.identity(), maxConcurrency); } @@ -3282,7 +3650,7 @@ public static Flowable merge(@NonNull Iterable - * + * *

* You can combine the items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by * using the {@code merge} method. @@ -3311,8 +3679,8 @@ public static Flowable merge(@NonNull Iterable the common element base type * @param sources * a {@code Publisher} that emits {@code Publisher}s - * @return a {@code Flowable} that emits items that are the result of flattening the {@code Publisher}s emitted by the - * {@code source} {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(Publisher) */ @@ -3320,7 +3688,7 @@ public static Flowable merge(@NonNull Iterable Flowable merge(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable merge(@NonNull Publisher<@NonNull ? extends Publisher> sources) { return merge(sources, bufferSize()); } @@ -3329,7 +3697,7 @@ public static Flowable merge(@NonNull Publisher - * + * *

* You can combine the items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by * using the {@code merge} method. @@ -3359,8 +3727,8 @@ public static Flowable merge(@NonNull PublisherReactiveX operators documentation: Merge @@ -3372,14 +3740,14 @@ public static Flowable merge(@NonNull Publisher Flowable merge(@NonNull Publisher> sources, int maxConcurrency) { + public static <@NonNull T> Flowable merge(@NonNull Publisher<@NonNull ? extends Publisher> sources, int maxConcurrency) { return fromPublisher(sources).flatMap((Function)Functions.identity(), maxConcurrency); } /** - * Flattens an Array of {@link Publisher}s into one {@code Publisher}, without any transformation. + * Flattens an array of {@link Publisher}s into one {@code Publisher}, without any transformation. *

- * + * *

* You can combine items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by * using the {@code merge} method. @@ -3407,7 +3775,8 @@ public static Flowable merge(@NonNull Publisher the common element base type * @param sources * the array of {@code Publisher}s - * @return a {@code Flowable} that emits all of the items emitted by the {@code Publisher}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeArrayDelayError(Publisher...) */ @@ -3417,14 +3786,14 @@ public static Flowable merge(@NonNull Publisher Flowable mergeArray(@NonNull Publisher... sources) { + public static <@NonNull T> Flowable mergeArray(@NonNull Publisher... sources) { return fromArray(sources).flatMap((Function)Functions.identity(), sources.length); } /** * Flattens two {@link Publisher}s into a single {@code Publisher}, without any transformation. *

- * + * *

* You can combine items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by * using the {@code merge} method. @@ -3454,7 +3823,8 @@ public static Flowable mergeArray(@NonNull Publisher... sour * a {@code Publisher} to be merged * @param source2 * a {@code Publisher} to be merged - * @return a {@code Flowable} that emits all of the items emitted by the source {@code Publisher}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(Publisher, Publisher) */ @@ -3463,7 +3833,7 @@ public static Flowable mergeArray(@NonNull Publisher... sour @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable merge(@NonNull Publisher source1, @NonNull Publisher source2) { + public static <@NonNull T> Flowable merge(@NonNull Publisher source1, @NonNull Publisher source2) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); return fromArray(source1, source2).flatMap((Function)Functions.identity(), false, 2); @@ -3472,7 +3842,7 @@ public static Flowable merge(@NonNull Publisher source1, @No /** * Flattens three {@link Publisher}s into a single {@code Publisher}, without any transformation. *

- * + * *

* You can combine items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by * using the {@code merge} method. @@ -3504,7 +3874,8 @@ public static Flowable merge(@NonNull Publisher source1, @No * a {@code Publisher} to be merged * @param source3 * a {@code Publisher} to be merged - * @return a {@code Flowable} that emits all of the items emitted by the source {@code Publisher}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(Publisher, Publisher, Publisher) */ @@ -3513,7 +3884,7 @@ public static Flowable merge(@NonNull Publisher source1, @No @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable merge(@NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3) { + public static <@NonNull T> Flowable merge(@NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); Objects.requireNonNull(source3, "source3 is null"); @@ -3523,7 +3894,7 @@ public static Flowable merge(@NonNull Publisher source1, @No /** * Flattens four {@link Publisher}s into a single {@code Publisher}, without any transformation. *

- * + * *

* You can combine items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by * using the {@code merge} method. @@ -3557,7 +3928,8 @@ public static Flowable merge(@NonNull Publisher source1, @No * a {@code Publisher} to be merged * @param source4 * a {@code Publisher} to be merged - * @return a {@code Flowable} that emits all of the items emitted by the source {@code Publisher}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(Publisher, Publisher, Publisher, Publisher) */ @@ -3566,7 +3938,7 @@ public static Flowable merge(@NonNull Publisher source1, @No @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable merge( + public static <@NonNull T> Flowable merge( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4) { Objects.requireNonNull(source1, "source1 is null"); @@ -3585,7 +3957,7 @@ public static Flowable merge( * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that * error notification until all of the merged {@code Publisher}s have finished emitting items. *

- * + * *

* Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only * invoke the {@code onError} method of its {@code Subscriber}s once. @@ -3600,8 +3972,8 @@ public static Flowable merge( * @param the common element base type * @param sources * the {@code Iterable} of {@code Publisher}s - * @return a {@code Flowable} that emits items that are the result of flattening the items emitted by the - * {@code Publisher}s in the {@code Iterable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -3609,7 +3981,7 @@ public static Flowable merge( @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable mergeDelayError(@NonNull Iterable> sources) { + public static <@NonNull T> Flowable mergeDelayError(@NonNull Iterable<@NonNull ? extends Publisher> sources) { return fromIterable(sources).flatMap((Function)Functions.identity(), true); } @@ -3622,7 +3994,7 @@ public static Flowable mergeDelayError(@NonNull Iterable - * + * *

* Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only * invoke the {@code onError} method of its {@code Subscriber}s once. @@ -3641,8 +4013,9 @@ public static Flowable mergeDelayError(@NonNull IterableReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -3650,7 +4023,7 @@ public static Flowable mergeDelayError(@NonNull Iterable Flowable mergeDelayError(@NonNull Iterable> sources, int maxConcurrency, int bufferSize) { + public static <@NonNull T> Flowable mergeDelayError(@NonNull Iterable<@NonNull ? extends Publisher> sources, int maxConcurrency, int bufferSize) { return fromIterable(sources).flatMap((Function)Functions.identity(), true, maxConcurrency, bufferSize); } @@ -3663,7 +4036,7 @@ public static Flowable mergeDelayError(@NonNull Iterable - * + * *

* Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only * invoke the {@code onError} method of its {@code Subscriber}s once. @@ -3682,8 +4055,9 @@ public static Flowable mergeDelayError(@NonNull IterableReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -3692,7 +4066,7 @@ public static Flowable mergeDelayError(@NonNull Iterable Flowable mergeArrayDelayError(int maxConcurrency, int bufferSize, @NonNull Publisher... sources) { + public static <@NonNull T> Flowable mergeArrayDelayError(int maxConcurrency, int bufferSize, @NonNull Publisher... sources) { return fromArray(sources).flatMap((Function)Functions.identity(), true, maxConcurrency, bufferSize); } @@ -3705,7 +4079,7 @@ public static Flowable mergeArrayDelayError(int maxConcurrency, int buffe * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that * error notification until all of the merged {@code Publisher}s have finished emitting items. *

- * + * *

* Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only * invoke the {@code onError} method of its {@code Subscriber}s once. @@ -3722,8 +4096,9 @@ public static Flowable mergeArrayDelayError(int maxConcurrency, int buffe * the {@code Iterable} of {@code Publisher}s * @param maxConcurrency * the maximum number of {@code Publisher}s that may be subscribed to concurrently - * @return a {@code Flowable} that emits items that are the result of flattening the items emitted by the - * {@code Publisher}s in the {@code Iterable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -3731,7 +4106,7 @@ public static Flowable mergeArrayDelayError(int maxConcurrency, int buffe @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable mergeDelayError(@NonNull Iterable> sources, int maxConcurrency) { + public static <@NonNull T> Flowable mergeDelayError(@NonNull Iterable<@NonNull ? extends Publisher> sources, int maxConcurrency) { return fromIterable(sources).flatMap((Function)Functions.identity(), true, maxConcurrency); } @@ -3744,7 +4119,7 @@ public static Flowable mergeDelayError(@NonNull Iterable - * + * *

* Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only * invoke the {@code onError} method of its {@code Subscriber}s once. @@ -3760,15 +4135,15 @@ public static Flowable mergeDelayError(@NonNull Iterable the common element base type * @param sources * a {@code Publisher} that emits {@code Publisher}s - * @return a {@code Flowable} that emits all of the items emitted by the {@code Publisher}s emitted by the - * {@code source} {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable mergeDelayError(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable mergeDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources) { return mergeDelayError(sources, bufferSize()); } @@ -3782,7 +4157,7 @@ public static Flowable mergeDelayError(@NonNull Publisher - * + * *

* Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only * invoke the {@code onError} method of its {@code Subscriber}s once. @@ -3799,8 +4174,9 @@ public static Flowable mergeDelayError(@NonNull PublisherReactiveX operators documentation: Merge * @since 2.0 */ @@ -3809,7 +4185,7 @@ public static Flowable mergeDelayError(@NonNull Publisher Flowable mergeDelayError(@NonNull Publisher> sources, int maxConcurrency) { + public static <@NonNull T> Flowable mergeDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources, int maxConcurrency) { return fromPublisher(sources).flatMap((Function)Functions.identity(), true, maxConcurrency); } @@ -3822,7 +4198,7 @@ public static Flowable mergeDelayError(@NonNull Publisher - * + * *

* Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only * invoke the {@code onError} method of its {@code Subscriber}s once. @@ -3837,8 +4213,8 @@ public static Flowable mergeDelayError(@NonNull Publisher the common element base type * @param sources * the array of {@code Publisher}s - * @return a {@code Flowable} that emits items that are the result of flattening the items emitted by the - * {@code Publisher}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -3847,7 +4223,7 @@ public static Flowable mergeDelayError(@NonNull Publisher Flowable mergeArrayDelayError(@NonNull Publisher... sources) { + public static <@NonNull T> Flowable mergeArrayDelayError(@NonNull Publisher... sources) { return fromArray(sources).flatMap((Function)Functions.identity(), true, sources.length); } @@ -3860,7 +4236,7 @@ public static Flowable mergeArrayDelayError(@NonNull Publisher - * + * *

* Even if both merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only * invoke the {@code onError} method of its {@code Subscriber}s once. @@ -3877,7 +4253,8 @@ public static Flowable mergeArrayDelayError(@NonNull PublisherReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -3885,7 +4262,7 @@ public static Flowable mergeArrayDelayError(@NonNull Publisher Flowable mergeDelayError(@NonNull Publisher source1, @NonNull Publisher source2) { + public static <@NonNull T> Flowable mergeDelayError(@NonNull Publisher source1, @NonNull Publisher source2) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); return fromArray(source1, source2).flatMap((Function)Functions.identity(), true, 2); @@ -3901,7 +4278,7 @@ public static Flowable mergeDelayError(@NonNull Publisher so * from propagating that error notification until all of the merged {@code Publisher}s have finished emitting * items. *

- * + * *

* Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only * invoke the {@code onError} method of its {@code Subscriber}s once. @@ -3920,7 +4297,8 @@ public static Flowable mergeDelayError(@NonNull Publisher so * a {@code Publisher} to be merged * @param source3 * a {@code Publisher} to be merged - * @return a {@code Flowable} that emits all of the items that are emitted by the source {@code Publisher}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} * @see ReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -3928,7 +4306,7 @@ public static Flowable mergeDelayError(@NonNull Publisher so @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable mergeDelayError(@NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3) { + public static <@NonNull T> Flowable mergeDelayError(@NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); Objects.requireNonNull(source3, "source3 is null"); @@ -3945,7 +4323,7 @@ public static Flowable mergeDelayError(@NonNull Publisher so * will refrain from propagating that error notification until all of the merged {@code Publisher}s have finished * emitting items. *

- * + * *

* Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only * invoke the {@code onError} method of its {@code Subscriber}s once. @@ -3966,7 +4344,8 @@ public static Flowable mergeDelayError(@NonNull Publisher so * a {@code Publisher} to be merged * @param source4 * a {@code Publisher} to be merged - * @return a {@code Flowable} that emits all of the items that are emitted by the source {@code Publisher}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} * @see ReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -3974,7 +4353,7 @@ public static Flowable mergeDelayError(@NonNull Publisher so @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable mergeDelayError( + public static <@NonNull T> Flowable mergeDelayError( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4) { Objects.requireNonNull(source1, "source1 is null"); @@ -3987,7 +4366,7 @@ public static Flowable mergeDelayError( /** * Returns a {@code Flowable} that never sends any items or notifications to a {@link Subscriber}. *

- * + * *

* This {@link Publisher} is useful primarily for testing purposes. *

@@ -3999,7 +4378,7 @@ public static Flowable mergeDelayError( * * @param * the type of items (not) emitted by the {@code Publisher} - * @return a {@code Flowable} that never emits any items or sends any notifications to a {@code Subscriber} + * @return the shared {@code Flowable} instance * @see ReactiveX operators documentation: Never */ @CheckReturnValue @@ -4007,14 +4386,14 @@ public static Flowable mergeDelayError( @SchedulerSupport(SchedulerSupport.NONE) @SuppressWarnings("unchecked") @NonNull - public static Flowable never() { + public static <@NonNull T> Flowable never() { return RxJavaPlugins.onAssembly((Flowable) FlowableNever.INSTANCE); } /** * Returns a {@code Flowable} that emits a sequence of {@link Integer}s within a specified range. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream and signals values on-demand (i.e., when requested).
@@ -4026,11 +4405,13 @@ public static Flowable never() { * the value of the first {@code Integer} in the sequence * @param count * the number of sequential {@code Integer}s to generate - * @return a {@code Flowable} that emits a range of sequential {@code Integer}s + * @return the new {@code Flowable} instance * @throws IllegalArgumentException * if {@code count} is less than zero, or if {@code start} + {@code count} − 1 exceeds * {@link Integer#MAX_VALUE} * @see ReactiveX operators documentation: Range + * @see #rangeLong(long, long) + * @see #intervalRange(long, long, long, long, TimeUnit) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @@ -4055,7 +4436,7 @@ public static Flowable range(int start, int count) { /** * Returns a {@code Flowable} that emits a sequence of {@link Long}s within a specified range. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream and signals values on-demand (i.e., when requested).
@@ -4067,7 +4448,7 @@ public static Flowable range(int start, int count) { * the value of the first {@code Long} in the sequence * @param count * the number of sequential {@code Long}s to generate - * @return a {@code Flowable} that emits a range of sequential {@code Long}s + * @return the new {@code Flowable} instance * @throws IllegalArgumentException * if {@code count} is less than zero, or if {@code start} + {@code count} − 1 exceeds * {@link Long#MAX_VALUE} @@ -4102,7 +4483,7 @@ public static Flowable rangeLong(long start, long count) { * Returns a {@link Single} that emits a {@link Boolean} value that indicates whether two {@link Publisher} sequences are the * same by comparing the items emitted by each {@code Publisher} pairwise. *

- * + * *

*
Backpressure:
*
This operator honors downstream backpressure and expects both of its sources @@ -4117,14 +4498,15 @@ public static Flowable rangeLong(long start, long count) { * the second {@code Publisher} to compare * @param * the type of items emitted by each {@code Publisher} - * @return a {@code Single} that emits a {@code Boolean} value that indicates whether the two sequences are the same + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @see ReactiveX operators documentation: SequenceEqual */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Single sequenceEqual(@NonNull Publisher source1, @NonNull Publisher source2) { + public static <@NonNull T> Single sequenceEqual(@NonNull Publisher source1, @NonNull Publisher source2) { return sequenceEqual(source1, source2, ObjectHelper.equalsPredicate(), bufferSize()); } @@ -4133,7 +4515,7 @@ public static Single sequenceEqual(@NonNull Publisher * same by comparing the items emitted by each {@code Publisher} pairwise based on the results of a specified * equality function. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The source {@code Publisher}s are expected to honor @@ -4150,15 +4532,15 @@ public static Single sequenceEqual(@NonNull Publisher * a function used to compare items emitted by each {@code Publisher} * @param * the type of items emitted by each {@code Publisher} - * @return a {@code Single} that emits a {@code Boolean} value that indicates whether the two {@code Publisher} sequences - * are the same according to the specified function + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code isEqual} is {@code null} * @see ReactiveX operators documentation: SequenceEqual */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Single sequenceEqual(@NonNull Publisher source1, @NonNull Publisher source2, + public static <@NonNull T> Single sequenceEqual(@NonNull Publisher source1, @NonNull Publisher source2, @NonNull BiPredicate isEqual) { return sequenceEqual(source1, source2, isEqual, bufferSize()); } @@ -4168,7 +4550,7 @@ public static Single sequenceEqual(@NonNull Publisher * same by comparing the items emitted by each {@code Publisher} pairwise based on the results of a specified * equality function. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The source {@code Publisher}s are expected to honor @@ -4187,15 +4569,16 @@ public static Single sequenceEqual(@NonNull Publisher * the number of items to prefetch from the first and second source {@code Publisher} * @param * the type of items emitted by each {@code Publisher} - * @return a {@code Single} that emits a {@code Boolean} value that indicates whether the two {@code Publisher} sequences - * are the same according to the specified function + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code isEqual} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: SequenceEqual */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Single sequenceEqual(@NonNull Publisher source1, @NonNull Publisher source2, + public static <@NonNull T> Single sequenceEqual(@NonNull Publisher source1, @NonNull Publisher source2, @NonNull BiPredicate isEqual, int bufferSize) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); @@ -4208,7 +4591,7 @@ public static Single sequenceEqual(@NonNull Publisher * Returns a {@link Single} that emits a {@link Boolean} value that indicates whether two {@link Publisher} sequences are the * same by comparing the items emitted by each {@code Publisher} pairwise. *

- * + * *

*
Backpressure:
*
This operator honors downstream backpressure and expects both of its sources @@ -4225,14 +4608,16 @@ public static Single sequenceEqual(@NonNull Publisher * the number of items to prefetch from the first and second source {@code Publisher} * @param * the type of items emitted by each {@code Publisher} - * @return a {@code Single} that emits a {@code Boolean} value that indicates whether the two sequences are the same + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: SequenceEqual */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Single sequenceEqual(@NonNull Publisher source1, @NonNull Publisher source2, int bufferSize) { + public static <@NonNull T> Single sequenceEqual(@NonNull Publisher source1, @NonNull Publisher source2, int bufferSize) { return sequenceEqual(source1, source2, ObjectHelper.equalsPredicate(), bufferSize); } @@ -4240,14 +4625,14 @@ public static Single sequenceEqual(@NonNull Publisher * Converts a {@link Publisher} that emits {@code Publisher}s into a {@code Publisher} that emits the items emitted by the * most recently emitted of those {@code Publisher}s. *

- * + * *

* {@code switchOnNext} subscribes to a {@code Publisher} that emits {@code Publisher}s. Each time it observes one of * these emitted {@code Publisher}s, the {@code Publisher} returned by {@code switchOnNext} begins emitting the items * emitted by that {@code Publisher}. When a new {@code Publisher} is emitted, {@code switchOnNext} stops emitting items * from the earlier-emitted {@code Publisher} and begins emitting items from the new one. *

- * The resulting {@code Publisher} completes if both the outer {@code Publisher} and the last inner {@code Publisher}, if any, complete. + * The resulting {@code Flowable} completes if both the outer {@code Publisher} and the last inner {@code Publisher}, if any, complete. * If the outer {@code Publisher} signals an {@code onError}, the inner {@code Publisher} is canceled and the error delivered in-sequence. *

*
Backpressure:
@@ -4264,8 +4649,9 @@ public static Single sequenceEqual(@NonNull Publisher * the source {@code Publisher} that emits {@code Publisher}s * @param bufferSize * the number of items to prefetch from the inner {@code Publisher}s - * @return a {@code Flowable} that emits the items emitted by the {@code Publisher} most recently emitted by the source - * {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Switch */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -4273,7 +4659,7 @@ public static Single sequenceEqual(@NonNull Publisher @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable switchOnNext(@NonNull Publisher> sources, int bufferSize) { + public static <@NonNull T> Flowable switchOnNext(@NonNull Publisher> sources, int bufferSize) { return fromPublisher(sources).switchMap((Function)Functions.identity(), bufferSize); } @@ -4281,14 +4667,14 @@ public static Flowable switchOnNext(@NonNull Publisher - * + * *

* {@code switchOnNext} subscribes to a {@code Publisher} that emits {@code Publisher}s. Each time it observes one of * these emitted {@code Publisher}s, the {@code Publisher} returned by {@code switchOnNext} begins emitting the items * emitted by that {@code Publisher}. When a new {@code Publisher} is emitted, {@code switchOnNext} stops emitting items * from the earlier-emitted {@code Publisher} and begins emitting items from the new one. *

- * The resulting {@code Publisher} completes if both the outer {@code Publisher} and the last inner {@code Publisher}, if any, complete. + * The resulting {@code Flowable} completes if both the outer {@code Publisher} and the last inner {@code Publisher}, if any, complete. * If the outer {@code Publisher} signals an {@code onError}, the inner {@code Publisher} is canceled and the error delivered in-sequence. *

*
Backpressure:
@@ -4303,8 +4689,8 @@ public static Flowable switchOnNext(@NonNull Publisher the item type * @param sources * the source {@code Publisher} that emits {@code Publisher}s - * @return a {@code Flowable} that emits the items emitted by the {@code Publisher} most recently emitted by the source - * {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Switch */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -4312,7 +4698,7 @@ public static Flowable switchOnNext(@NonNull Publisher Flowable switchOnNext(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable switchOnNext(@NonNull Publisher<@NonNull ? extends Publisher> sources) { return fromPublisher(sources).switchMap((Function)Functions.identity()); } @@ -4320,14 +4706,14 @@ public static Flowable switchOnNext(@NonNull Publisher - * + * *

* {@code switchOnNext} subscribes to a {@code Publisher} that emits {@code Publisher}s. Each time it observes one of * these emitted {@code Publisher}s, the {@code Publisher} returned by {@code switchOnNext} begins emitting the items * emitted by that {@code Publisher}. When a new {@code Publisher} is emitted, {@code switchOnNext} stops emitting items * from the earlier-emitted {@code Publisher} and begins emitting items from the new one. *

- * The resulting {@code Publisher} completes if both the main {@code Publisher} and the last inner {@code Publisher}, if any, complete. + * The resulting {@code Flowable} completes if both the main {@code Publisher} and the last inner {@code Publisher}, if any, complete. * If the main {@code Publisher} signals an {@code onError}, the termination of the last inner {@code Publisher} will emit that error as is * or wrapped into a {@link CompositeException} along with the other possible errors the former inner {@code Publisher}s signaled. *

@@ -4343,8 +4729,8 @@ public static Flowable switchOnNext(@NonNull Publisher the item type * @param sources * the source {@code Publisher} that emits {@code Publisher}s - * @return a {@code Flowable} that emits the items emitted by the {@code Publisher} most recently emitted by the source - * {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Switch * @since 2.0 */ @@ -4352,7 +4738,7 @@ public static Flowable switchOnNext(@NonNull Publisher Flowable switchOnNextDelayError(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable switchOnNextDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources) { return switchOnNextDelayError(sources, bufferSize()); } @@ -4360,14 +4746,14 @@ public static Flowable switchOnNextDelayError(@NonNull Publisher - * + * *

* {@code switchOnNext} subscribes to a {@code Publisher} that emits {@code Publisher}s. Each time it observes one of * these emitted {@code Publisher}s, the {@code Publisher} returned by {@code switchOnNext} begins emitting the items * emitted by that {@code Publisher}. When a new {@code Publisher} is emitted, {@code switchOnNext} stops emitting items * from the earlier-emitted {@code Publisher} and begins emitting items from the new one. *

- * The resulting {@code Publisher} completes if both the main {@code Publisher} and the last inner {@code Publisher}, if any, complete. + * The resulting {@code Flowable} completes if both the main {@code Publisher} and the last inner {@code Publisher}, if any, complete. * If the main {@code Publisher} signals an {@code onError}, the termination of the last inner {@code Publisher} will emit that error as is * or wrapped into a {@link CompositeException} along with the other possible errors the former inner {@code Publisher}s signaled. *

@@ -4385,8 +4771,9 @@ public static Flowable switchOnNextDelayError(@NonNull PublisherReactiveX operators documentation: Switch * @since 2.0 */ @@ -4394,14 +4781,14 @@ public static Flowable switchOnNextDelayError(@NonNull Publisher Flowable switchOnNextDelayError(@NonNull Publisher> sources, int prefetch) { + public static <@NonNull T> Flowable switchOnNextDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources, int prefetch) { return fromPublisher(sources).switchMapDelayError(Functions.>identity(), prefetch); } /** * Returns a {@code Flowable} that emits {@code 0L} after a specified delay, and then completes. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time. If the downstream needs a slower rate @@ -4414,7 +4801,8 @@ public static Flowable switchOnNextDelayError(@NonNull PublisherReactiveX operators documentation: Timer */ @CheckReturnValue @@ -4429,7 +4817,7 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit) { * Returns a {@code Flowable} that emits {@code 0L} after a specified delay, on a specified {@link Scheduler}, and then * completes. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time. If the downstream needs a slower rate @@ -4444,8 +4832,8 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit) { * time units to use for {@code delay} * @param scheduler * the {@code Scheduler} to use for scheduling the item - * @return a {@code Flowable} that emits {@code 0L} after a specified delay, on a specified {@code Scheduler}, and then - * completes + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Timer */ @CheckReturnValue @@ -4473,6 +4861,7 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull * @param the value type emitted * @param onSubscribe the {@code Publisher} instance to wrap * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onSubscribe} is {@code null} * @throws IllegalArgumentException if {@code onSubscribe} is a subclass of {@code Flowable}; such * instances don't need conversion and is possibly a port remnant from 1.x or one should use {@link #hide()} * instead. @@ -4481,7 +4870,7 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull @NonNull @BackpressureSupport(BackpressureKind.NONE) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable unsafeCreate(@NonNull Publisher onSubscribe) { + public static <@NonNull T> Flowable unsafeCreate(@NonNull Publisher onSubscribe) { Objects.requireNonNull(onSubscribe, "onSubscribe is null"); if (onSubscribe instanceof Flowable) { throw new IllegalArgumentException("unsafeCreate(Flowable) should be upgraded"); @@ -4490,9 +4879,11 @@ public static Flowable unsafeCreate(@NonNull Publisher onSubscribe) { } /** - * Constructs a {@link Publisher} that creates a dependent resource object which is disposed of on cancellation. + * Constructs a {@code Flowable} that creates a dependent resource object, a {@link Publisher} with + * that resource and calls the provided {@code resourceDisposer} function if this inner source terminates or the + * downstream cancels the flow. *

- * + * *

*
Backpressure:
*
The operator is a pass-through for backpressure and otherwise depends on the @@ -4507,30 +4898,29 @@ public static Flowable unsafeCreate(@NonNull Publisher onSubscribe) { * the factory function to create a resource object that depends on the {@code Publisher} * @param sourceSupplier * the factory function to create a {@code Publisher} - * @param resourceDisposer + * @param resourceCleanup * the function that will dispose of the resource - * @return the {@code Publisher} whose lifetime controls the lifetime of the dependent resource object + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code resourceSupplier}, {@code sourceSupplier} or {@code resourceCleanup} is {@code null} * @see ReactiveX operators documentation: Using */ @CheckReturnValue @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable using( + public static <@NonNull T, @NonNull D> Flowable using( @NonNull Supplier resourceSupplier, - @NonNull Function> sourceSupplier, - @NonNull Consumer resourceDisposer) { - return using(resourceSupplier, sourceSupplier, resourceDisposer, true); + @NonNull Function> sourceSupplier, + @NonNull Consumer resourceCleanup) { + return using(resourceSupplier, sourceSupplier, resourceCleanup, true); } /** - * Constructs a {@link Publisher} that creates a dependent resource object which is disposed of just before - * termination if you have set {@code disposeEagerly} to {@code true} and cancellation does not occur - * before termination. Otherwise, resource disposal will occur on cancellation. Eager disposal is - * particularly appropriate for a synchronous {@code Publisher} that reuses resources. {@code disposeAction} will - * only be called once per subscription. + * Constructs a {@code Flowable} that creates a dependent resource object, a {@link Publisher} with + * that resource and calls the provided {@code resourceDisposer} function if this inner source terminates or the + * downstream disposes the flow; doing it before these end-states have been reached if {@code eager == true}, after otherwise. *

- * + * *

*
Backpressure:
*
The operator is a pass-through for backpressure and otherwise depends on the @@ -4545,14 +4935,15 @@ public static Flowable using( * the factory function to create a resource object that depends on the {@code Publisher} * @param sourceSupplier * the factory function to create a {@code Publisher} - * @param resourceDisposer + * @param resourceCleanup * the function that will dispose of the resource * @param eager - * If {@code true} then resource disposal will happen either on a {@code cancel()} call before the upstream is disposed + * If {@code true}, the resource disposal will happen either on a {@code cancel()} call before the upstream is disposed * or just before the emission of a terminal event ({@code onComplete} or {@code onError}). * If {@code false} the resource disposal will happen either on a {@code cancel()} call after the upstream is disposed * or just after the emission of a terminal event ({@code onComplete} or {@code onError}). - * @return the {@code Publisher} whose lifetime controls the lifetime of the dependent resource object + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code resourceSupplier}, {@code sourceSupplier} or {@code resourceCleanup} is {@code null} * @see ReactiveX operators documentation: Using * @since 2.0 */ @@ -4560,15 +4951,15 @@ public static Flowable using( @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable using( + public static <@NonNull T, @NonNull D> Flowable using( @NonNull Supplier resourceSupplier, - @NonNull Function> sourceSupplier, - @NonNull Consumer resourceDisposer, + @NonNull Function> sourceSupplier, + @NonNull Consumer resourceCleanup, boolean eager) { Objects.requireNonNull(resourceSupplier, "resourceSupplier is null"); Objects.requireNonNull(sourceSupplier, "sourceSupplier is null"); - Objects.requireNonNull(resourceDisposer, "resourceDisposer is null"); - return RxJavaPlugins.onAssembly(new FlowableUsing(resourceSupplier, sourceSupplier, resourceDisposer, eager)); + Objects.requireNonNull(resourceCleanup, "resourceCleanup is null"); + return RxJavaPlugins.onAssembly(new FlowableUsing(resourceSupplier, sourceSupplier, resourceCleanup, eager)); } /** @@ -4580,7 +4971,7 @@ public static Flowable using( * the second item emitted by the new {@code Publisher} will be the result of the function applied to the second * item emitted by each of those {@code Publisher}s; and so forth. *

- * The resulting {@code Publisher} returned from {@code zip} will invoke {@code onNext} as many times as + * The resulting {@code Flowable} returned from {@code zip} will invoke {@code onNext} as many times as * the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest items. *

* The operator subscribes to its sources in the order they are specified and completes eagerly if @@ -4595,7 +4986,7 @@ public static Flowable using( * use {@link #doOnCancel(Action)} as well or use {@code using()} to do cleanup in case of completion * or cancellation. *

- * + * *

*
Backpressure:
*
The operator expects backpressure from the sources and honors backpressure from the downstream. @@ -4611,15 +5002,16 @@ public static Flowable using( * an {@code Iterable} of source {@code Publisher}s * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results in - * an item that will be emitted by the resulting {@code Publisher} - * @return a {@code Flowable} that emits the zipped results + * an item that will be emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable zip(@NonNull Iterable> sources, @NonNull Function zipper) { + public static <@NonNull T, @NonNull R> Flowable zip(@NonNull Iterable<@NonNull ? extends Publisher> sources, @NonNull Function zipper) { Objects.requireNonNull(zipper, "zipper is null"); Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new FlowableZip<>(null, sources, zipper, bufferSize(), false)); @@ -4634,7 +5026,7 @@ public static Flowable zip(@NonNull Iterable - * The resulting {@code Publisher} returned from {@code zip} will invoke {@code onNext} as many times as + * The resulting {@code Floawble} returned from {@code zip} will invoke {@code onNext} as many times as * the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest items. *

* The operator subscribes to its sources in the order they are specified and completes eagerly if @@ -4649,7 +5041,7 @@ public static Flowable zip(@NonNull Iterable - * + * *

*
Backpressure:
*
The operator expects backpressure from the sources and honors backpressure from the downstream. @@ -4664,21 +5056,23 @@ public static Flowable zip(@NonNull Iterable the common source value type * @param the zipped result type - * @return a {@code Flowable} that emits the zipped results + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} or {@code zipper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable zip(@NonNull Iterable> sources, + public static <@NonNull T, @NonNull R> Flowable zip(@NonNull Iterable<@NonNull ? extends Publisher> sources, @NonNull Function zipper, boolean delayError, int bufferSize) { Objects.requireNonNull(zipper, "zipper is null"); @@ -4691,14 +5085,14 @@ public static Flowable zip(@NonNull Iterable - * + * *

* {@code zip} applies this function in strict sequence, so the first item emitted by the new {@code Publisher} * will be the result of the function applied to the first item emitted by {@code o1} and the first item * emitted by {@code o2}; the second item emitted by the new {@code Publisher} will be the result of the function * applied to the second item emitted by {@code o1} and the second item emitted by {@code o2}; and so forth. *

- * The resulting {@code Publisher} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} + * The resulting {@code Flowable} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} * as many times as the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest * items. *

@@ -4731,15 +5125,16 @@ public static Flowable zip(@NonNull IterableReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable zip( + public static <@NonNull T1, @NonNull T2, @NonNull R> Flowable zip( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull BiFunction zipper) { Objects.requireNonNull(source1, "source1 is null"); @@ -4752,14 +5147,14 @@ public static Flowable zip( * Returns a {@code Flowable} that emits the results of a specified combiner function applied to combinations of * two items emitted, in sequence, by two other {@link Publisher}s. *

- * + * *

* {@code zip} applies this function in strict sequence, so the first item emitted by the new {@code Publisher} * will be the result of the function applied to the first item emitted by {@code o1} and the first item * emitted by {@code o2}; the second item emitted by the new {@code Publisher} will be the result of the function * applied to the second item emitted by {@code o1} and the second item emitted by {@code o2}; and so forth. *

- * The resulting {@code Publisher} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} + * The resulting {@code Flowable} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} * as many times as the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest * items. *

@@ -4792,16 +5187,17 @@ public static Flowable zip( * a second source {@code Publisher} * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results - * in an item that will be emitted by the resulting {@code Publisher} + * in an item that will be emitted by the resulting {@code Flowable} * @param delayError delay errors from any of the source {@code Publisher}s till the other terminates - * @return a {@code Flowable} that emits the zipped results + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable zip( + public static <@NonNull T1, @NonNull T2, @NonNull R> Flowable zip( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull BiFunction zipper, boolean delayError) { Objects.requireNonNull(source1, "source1 is null"); @@ -4814,14 +5210,14 @@ public static Flowable zip( * Returns a {@code Flowable} that emits the results of a specified combiner function applied to combinations of * two items emitted, in sequence, by two other {@link Publisher}s. *

- * + * *

* {@code zip} applies this function in strict sequence, so the first item emitted by the new {@code Publisher} * will be the result of the function applied to the first item emitted by {@code o1} and the first item * emitted by {@code o2}; the second item emitted by the new {@code Publisher} will be the result of the function * applied to the second item emitted by {@code o1} and the second item emitted by {@code o2}; and so forth. *

- * The resulting {@code Publisher} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} + * The resulting {@code Flowable} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} * as many times as the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest * items. *

@@ -4854,17 +5250,19 @@ public static Flowable zip( * a second source {@code Publisher} * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results - * in an item that will be emitted by the resulting {@code Publisher} + * in an item that will be emitted by the resulting {@code Flowable} * @param delayError delay errors from any of the source {@code Publisher}s till the other terminates * @param bufferSize the number of elements to prefetch from each source {@code Publisher} - * @return a {@code Flowable} that emits the zipped results + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code zipper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable zip( + public static <@NonNull T1, @NonNull T2, @NonNull R> Flowable zip( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull BiFunction zipper, boolean delayError, int bufferSize) { Objects.requireNonNull(source1, "source1 is null"); @@ -4877,7 +5275,7 @@ public static Flowable zip( * Returns a {@code Flowable} that emits the results of a specified combiner function applied to combinations of * three items emitted, in sequence, by three other {@link Publisher}s. *

- * + * *

* {@code zip} applies this function in strict sequence, so the first item emitted by the new {@code Publisher} * will be the result of the function applied to the first item emitted by {@code o1}, the first item @@ -4885,7 +5283,7 @@ public static Flowable zip( * {@code Publisher} will be the result of the function applied to the second item emitted by {@code o1}, the * second item emitted by {@code o2}, and the second item emitted by {@code o3}; and so forth. *

- * The resulting {@code Publisher} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} + * The resulting {@code Flowable} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} * as many times as the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest * items. *

@@ -4921,15 +5319,16 @@ public static Flowable zip( * a third source {@code Publisher} * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results in - * an item that will be emitted by the resulting {@code Publisher} - * @return a {@code Flowable} that emits the zipped results + * an item that will be emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull R> Flowable zip( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Function3 zipper) { Objects.requireNonNull(source1, "source1 is null"); @@ -4943,7 +5342,7 @@ public static Flowable zip( * Returns a {@code Flowable} that emits the results of a specified combiner function applied to combinations of * four items emitted, in sequence, by four other {@link Publisher}s. *

- * + * *

* {@code zip} applies this function in strict sequence, so the first item emitted by the new {@code Publisher} * will be the result of the function applied to the first item emitted by {@code o1}, the first item @@ -4951,7 +5350,7 @@ public static Flowable zip( * the second item emitted by the new {@code Publisher} will be the result of the function applied to the second * item emitted by each of those {@code Publisher}s; and so forth. *

- * The resulting {@code Publisher} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} + * The resulting {@code Flowable} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} * as many times as the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest * items. *

@@ -4990,15 +5389,17 @@ public static Flowable zip( * a fourth source {@code Publisher} * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results in - * an item that will be emitted by the resulting {@code Publisher} - * @return a {@code Flowable} that emits the zipped results + * an item that will be emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull R> Flowable zip( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4, @NonNull Function4 zipper) { @@ -5014,7 +5415,7 @@ public static Flowable zip( * Returns a {@code Flowable} that emits the results of a specified combiner function applied to combinations of * five items emitted, in sequence, by five other {@link Publisher}s. *

- * + * *

* {@code zip} applies this function in strict sequence, so the first item emitted by the new {@code Publisher} * will be the result of the function applied to the first item emitted by {@code o1}, the first item @@ -5022,7 +5423,7 @@ public static Flowable zip( * the first item emitted by {@code o5}; the second item emitted by the new {@code Publisher} will be the result of * the function applied to the second item emitted by each of those {@code Publisher}s; and so forth. *

- * The resulting {@code Publisher} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} + * The resulting {@code Flowable} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} * as many times as the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest * items. *

@@ -5064,15 +5465,17 @@ public static Flowable zip( * a fifth source {@code Publisher} * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results in - * an item that will be emitted by the resulting {@code Publisher} - * @return a {@code Flowable} that emits the zipped results + * an item that will be emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull R> Flowable zip( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4, @NonNull Publisher source5, @NonNull Function5 zipper) { @@ -5089,14 +5492,14 @@ public static Flowable zip( * Returns a {@code Flowable} that emits the results of a specified combiner function applied to combinations of * six items emitted, in sequence, by six other {@link Publisher}s. *

- * + * *

* {@code zip} applies this function in strict sequence, so the first item emitted by the new {@code Publisher} * will be the result of the function applied to the first item emitted by each source {@code Publisher}, the * second item emitted by the new {@code Publisher} will be the result of the function applied to the second item * emitted by each of those {@code Publisher}s, and so forth. *

- * The resulting {@code Publisher} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} + * The resulting {@code Flowable} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} * as many times as the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest * items. *

@@ -5141,15 +5544,18 @@ public static Flowable zip( * a sixth source {@code Publisher} * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results in - * an item that will be emitted by the resulting {@code Publisher} - * @return a {@code Flowable} that emits the zipped results + * an item that will be emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6} + * or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull R> Flowable zip( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4, @NonNull Publisher source5, @NonNull Publisher source6, @NonNull Function6 zipper) { @@ -5167,14 +5573,14 @@ public static Flowable zip( * Returns a {@code Flowable} that emits the results of a specified combiner function applied to combinations of * seven items emitted, in sequence, by seven other {@link Publisher}s. *

- * + * *

* {@code zip} applies this function in strict sequence, so the first item emitted by the new {@code Publisher} * will be the result of the function applied to the first item emitted by each source {@code Publisher}, the * second item emitted by the new {@code Publisher} will be the result of the function applied to the second item * emitted by each of those {@code Publisher}s, and so forth. *

- * The resulting {@code Publisher} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} + * The resulting {@code Flowable} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} * as many times as the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest * items. *

@@ -5222,15 +5628,18 @@ public static Flowable zip( * a seventh source {@code Publisher} * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results in - * an item that will be emitted by the resulting {@code Publisher} - * @return a {@code Flowable} that emits the zipped results + * an item that will be emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull R> Flowable zip( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4, @NonNull Publisher source5, @NonNull Publisher source6, @NonNull Publisher source7, @@ -5250,14 +5659,14 @@ public static Flowable zip( * Returns a {@code Flowable} that emits the results of a specified combiner function applied to combinations of * eight items emitted, in sequence, by eight other {@link Publisher}s. *

- * + * *

* {@code zip} applies this function in strict sequence, so the first item emitted by the new {@code Publisher} * will be the result of the function applied to the first item emitted by each source {@code Publisher}, the * second item emitted by the new {@code Publisher} will be the result of the function applied to the second item * emitted by each of those {@code Publisher}s, and so forth. *

- * The resulting {@code Publisher} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} + * The resulting {@code Flowable} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} * as many times as the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest * items. *

@@ -5308,15 +5717,18 @@ public static Flowable zip( * an eighth source {@code Publisher} * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results in - * an item that will be emitted by the resulting {@code Publisher} - * @return a {@code Flowable} that emits the zipped results + * an item that will be emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7}, {@code source8} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull R> Flowable zip( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4, @NonNull Publisher source5, @NonNull Publisher source6, @NonNull Publisher source7, @NonNull Publisher source8, @@ -5337,14 +5749,14 @@ public static Flowable zip( * Returns a {@code Flowable} that emits the results of a specified combiner function applied to combinations of * nine items emitted, in sequence, by nine other {@link Publisher}s. *

- * + * *

* {@code zip} applies this function in strict sequence, so the first item emitted by the new {@code Publisher} * will be the result of the function applied to the first item emitted by each source {@code Publisher}, the * second item emitted by the new {@code Publisher} will be the result of the function applied to the second item * emitted by each of those {@code Publisher}s, and so forth. *

- * The resulting {@code Publisher} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} + * The resulting {@code Flowable} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} * as many times as the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest * items. *

@@ -5398,15 +5810,19 @@ public static Flowable zip( * a ninth source {@code Publisher} * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results in - * an item that will be emitted by the resulting {@code Publisher} - * @return a {@code Flowable} that emits the zipped results + * an item that will be emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7}, {@code source8}, {@code source9} + * or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull T9, @NonNull R> Flowable zip( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4, @NonNull Publisher source5, @NonNull Publisher source6, @NonNull Publisher source7, @NonNull Publisher source8, @NonNull Publisher source9, @@ -5434,7 +5850,7 @@ public static Flowable zip( * the second item emitted by the new {@code Publisher} will be the result of the function applied to the second * item emitted by each of those {@code Publisher}s; and so forth. *

- * The resulting {@code Publisher} returned from {@code zip} will invoke {@code onNext} as many times as + * The resulting {@code Flowable} returned from {@code zip} will invoke {@code onNext} as many times as * the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest items. *

* The operator subscribes to its sources in the order they are specified and completes eagerly if @@ -5450,7 +5866,7 @@ public static Flowable zip( * use {@link #doOnCancel(Action)} as well or use {@code using()} to do cleanup in case of completion * or cancellation. *

- * + * *

*
Backpressure:
*
The operator expects backpressure from the sources and honors backpressure from the downstream. @@ -5466,12 +5882,14 @@ public static Flowable zip( * an array of source {@code Publisher}s * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results in - * an item that will be emitted by the resulting {@code Publisher} + * an item that will be emitted by the resulting {@code Flowable} * @param delayError * delay errors signaled by any of the source {@code Publisher} until all {@code Publisher}s terminate * @param bufferSize * the number of elements to prefetch from each source {@code Publisher} - * @return a {@code Flowable} that emits the zipped results + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} or {@code zipper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @@ -5479,8 +5897,9 @@ public static Flowable zip( @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs - public static Flowable zipArray(@NonNull Function zipper, + public static <@NonNull T, @NonNull R> Flowable zipArray(@NonNull Function zipper, boolean delayError, int bufferSize, @NonNull Publisher... sources) { + Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { return empty(); } @@ -5494,13 +5913,13 @@ public static Flowable zipArray(@NonNull Function - * + * *
*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an unbounded + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded * manner (i.e., without applying backpressure).
*
Scheduler:
*
{@code all} does not operate by default on a particular {@link Scheduler}.
@@ -5508,8 +5927,8 @@ public static Flowable zipArray(@NonNull FunctionReactiveX operators documentation: All */ @CheckReturnValue @@ -5525,20 +5944,29 @@ public final Single all(@NonNull Predicate predicate) { * Mirrors the {@link Publisher} (current or provided) that first either emits an item or sends a termination * notification. *

- * + * + *

+ * When the current {@code Flowable} signals an item or terminates first, the subscription to the other + * {@code Publisher} is canceled. If the other {@code Publisher} signals an item or terminates first, + * the subscription to the current {@code Flowable} is canceled. *

*
Backpressure:
*
The operator itself doesn't interfere with backpressure which is determined by the winning * {@code Publisher}'s backpressure behavior.
*
Scheduler:
*
{@code ambWith} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
+ * If the losing {@code Publisher} signals an error, the error is routed to the global + * error handler via {@link RxJavaPlugins#onError(Throwable)}. + *
*
* * @param other * a {@code Publisher} competing to react first. A subscription to this provided {@code Publisher} will occur after subscribing - * to the current {@code Publisher}. - * @return a {@code Flowable} that emits the same sequence as whichever of the source {@code Publisher}s first - * emitted an item or sent a termination notification + * to the current {@code Flowable}. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: Amb */ @CheckReturnValue @@ -5551,26 +5979,26 @@ public final Flowable ambWith(@NonNull Publisher other) { } /** - * Returns a {@link Single} that emits {@code true} if any item emitted by the source {@link Publisher} satisfies a + * Returns a {@link Single} that emits {@code true} if any item emitted by the current {@code Flowable} satisfies a * specified condition, otherwise {@code false}. Note: this always emits {@code false} if the - * source {@code Publisher} is empty. + * current {@code Flowable} is empty. *

- * + * *

* In Rx.Net this is the {@code any} operator but we renamed it in RxJava to better match Java naming * idioms. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an unbounded manner + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code any} does not operate by default on a particular {@link Scheduler}.
*
* * @param predicate - * the condition to test items emitted by the source {@code Publisher} - * @return a {@code Single} that emits a {@link Boolean} that indicates whether any item emitted by the source - * {@code Publisher} satisfies the {@code predicate} + * the condition to test items emitted by the current {@code Flowable} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @see ReactiveX operators documentation: Contains */ @CheckReturnValue @@ -5587,7 +6015,7 @@ public final Single any(@NonNull Predicate predicate) { * {@link NoSuchElementException} if it emits no items. *
*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code blockingFirst} does not operate by default on a particular {@link Scheduler}.
@@ -5597,7 +6025,7 @@ public final Single any(@NonNull Predicate predicate) { * {@link Error}s are rethrown as they are.
*
* - * @return the first item emitted by this {@code Flowable} + * @return the new {@code Flowable} instance * @throws NoSuchElementException * if this {@code Flowable} emits no items * @see ReactiveX documentation: First @@ -5621,7 +6049,7 @@ public final T blockingFirst() { * items. *
*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code blockingFirst} does not operate by default on a particular {@link Scheduler}.
@@ -5633,8 +6061,8 @@ public final T blockingFirst() { * * @param defaultItem * a default value to return if this {@code Flowable} emits no items - * @return the first item emitted by this {@code Flowable}, or the default value if it emits no - * items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX documentation: First */ @CheckReturnValue @@ -5642,6 +6070,7 @@ public final T blockingFirst() { @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final T blockingFirst(@NonNull T defaultItem) { + Objects.requireNonNull(defaultItem, "defaultItem is null"); BlockingFirstSubscriber s = new BlockingFirstSubscriber<>(); subscribe(s); T v = s.blockingGet(); @@ -5649,11 +6078,11 @@ public final T blockingFirst(@NonNull T defaultItem) { } /** - * Consumes the upstream {@code Flowable} in a blocking fashion and invokes the given + * Consumes the current {@code Flowable} in a blocking fashion and invokes the given * {@link Consumer} with each upstream item on the current thread until the * upstream terminates. *

- * + * *

* Note: the method will only return if the upstream terminates or the current * thread is interrupted. @@ -5675,6 +6104,7 @@ public final T blockingFirst(@NonNull T defaultItem) { * * @param onNext * the {@code Consumer} to invoke for each item emitted by the {@code Flowable} + * @throws NullPointerException if {@code onNext} is {@code null} * @throws RuntimeException * if an error occurs; {@code Error}s and {@code RuntimeException}s are rethrown * as they are, checked {@code Exception}s are wrapped into {@code RuntimeException}s @@ -5689,11 +6119,11 @@ public final void blockingForEach(@NonNull Consumer onNext) { } /** - * Consumes the upstream {@code Flowable} in a blocking fashion and invokes the given + * Consumes the current {@code Flowable} in a blocking fashion and invokes the given * {@link Consumer} with each upstream item on the current thread until the * upstream terminates. *

- * + * *

* Note: the method will only return if the upstream terminates or the current * thread is interrupted. @@ -5717,6 +6147,8 @@ public final void blockingForEach(@NonNull Consumer onNext) { * the {@code Consumer} to invoke for each item emitted by the {@code Flowable} * @param bufferSize * the number of items to prefetch upfront, then 75% of it after 75% received + * @throws NullPointerException if {@code onNext} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @throws RuntimeException * if an error occurs; {@code Error}s and {@code RuntimeException}s are rethrown * as they are, checked {@code Exception}s are wrapped into {@code RuntimeException}s @@ -5726,6 +6158,7 @@ public final void blockingForEach(@NonNull Consumer onNext) { @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) public final void blockingForEach(@NonNull Consumer onNext, int bufferSize) { + Objects.requireNonNull(onNext, "onNext is null"); Iterator it = blockingIterable(bufferSize).iterator(); while (it.hasNext()) { try { @@ -5741,7 +6174,7 @@ public final void blockingForEach(@NonNull Consumer onNext, int buffe /** * Converts this {@code Flowable} into an {@link Iterable}. *

- * + * *

*
Backpressure:
*
The operator expects the upstream to honor backpressure otherwise the returned @@ -5750,7 +6183,7 @@ public final void blockingForEach(@NonNull Consumer onNext, int buffe *
{@code blockingIterable} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an {@code Iterable} version of this {@code Flowable} + * @return the new {@code Iterable} instance * @see ReactiveX documentation: To */ @CheckReturnValue @@ -5764,7 +6197,7 @@ public final Iterable blockingIterable() { /** * Converts this {@code Flowable} into an {@link Iterable}. *

- * + * *

*
Backpressure:
*
The operator expects the upstream to honor backpressure otherwise the returned @@ -5775,7 +6208,8 @@ public final Iterable blockingIterable() { *
* * @param bufferSize the number of items to prefetch from the current {@code Flowable} - * @return an {@code Iterable} version of this {@code Flowable} + * @return the new {@code Iterable} instance + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX documentation: To */ @CheckReturnValue @@ -5791,10 +6225,10 @@ public final Iterable blockingIterable(int bufferSize) { * Returns the last item emitted by this {@code Flowable}, or throws * {@link NoSuchElementException} if this {@code Flowable} emits no items. *

- * + * *

*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code blockingLast} does not operate by default on a particular {@link Scheduler}.
@@ -5804,7 +6238,7 @@ public final Iterable blockingIterable(int bufferSize) { * {@link Error}s are rethrown as they are.
*
* - * @return the last item emitted by this {@code Flowable} + * @return the new {@code Flowable} instance * @throws NoSuchElementException * if this {@code Flowable} emits no items * @see ReactiveX documentation: Last @@ -5827,10 +6261,10 @@ public final T blockingLast() { * Returns the last item emitted by this {@code Flowable}, or a default value if it emits no * items. *

- * + * *

*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code blockingLast} does not operate by default on a particular {@link Scheduler}.
@@ -5842,8 +6276,8 @@ public final T blockingLast() { * * @param defaultItem * a default value to return if this {@code Flowable} emits no items - * @return the last item emitted by the {@code Flowable}, or the default value if it emits no - * items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX documentation: Last */ @CheckReturnValue @@ -5851,6 +6285,7 @@ public final T blockingLast() { @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final T blockingLast(@NonNull T defaultItem) { + Objects.requireNonNull(defaultItem, "defaultItem is null"); BlockingLastSubscriber s = new BlockingLastSubscriber<>(); subscribe(s); T v = s.blockingGet(); @@ -5868,13 +6303,13 @@ public final T blockingLast(@NonNull T defaultItem) { * event. *
*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code blockingLatest} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an {@code Iterable} that always returns the latest item emitted by this {@code Flowable} + * @return the new {@code Iterable} instance * @see ReactiveX documentation: First */ @CheckReturnValue @@ -5889,10 +6324,10 @@ public final Iterable blockingLatest() { * Returns an {@link Iterable} that always returns the item most recently emitted by this * {@code Flowable}. *

- * + * *

*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code blockingMostRecent} does not operate by default on a particular {@link Scheduler}.
@@ -5901,8 +6336,8 @@ public final Iterable blockingLatest() { * @param initialItem * the initial item that the {@code Iterable} sequence will yield if this * {@code Flowable} has not yet emitted an item - * @return an {@code Iterable} that on each iteration returns the item that this {@code Flowable} - * has most recently emitted + * @return the new {@code Iterable} instance + * @throws NullPointerException if {@code initialItem} is {@code null} * @see ReactiveX documentation: First */ @CheckReturnValue @@ -5910,6 +6345,7 @@ public final Iterable blockingLatest() { @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final Iterable blockingMostRecent(@NonNull T initialItem) { + Objects.requireNonNull(initialItem, "initialItem is null"); return new BlockingFlowableMostRecent<>(this, initialItem); } @@ -5917,17 +6353,16 @@ public final Iterable blockingMostRecent(@NonNull T initialItem) { * Returns an {@link Iterable} that blocks until this {@code Flowable} emits another item, then * returns that item. *

- * + * *

*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code blockingNext} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an {@code Iterable} that blocks upon each iteration until this {@code Flowable} emits - * a new item, whereupon the {@code Iterable} returns that item + * @return the new {@code Iterable} instance * @see ReactiveX documentation: TakeLast */ @CheckReturnValue @@ -5942,10 +6377,10 @@ public final Iterable blockingNext() { * If this {@code Flowable} completes after emitting a single item, return that item, otherwise * throw a {@link NoSuchElementException}. *

- * + * *

*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code blockingSingle} does not operate by default on a particular {@link Scheduler}.
@@ -5955,7 +6390,7 @@ public final Iterable blockingNext() { * {@link Error}s are rethrown as they are.
*
* - * @return the single item emitted by this {@code Flowable} + * @return the new {@code Flowable} instance * @see ReactiveX documentation: First */ @CheckReturnValue @@ -5971,10 +6406,10 @@ public final T blockingSingle() { * more than one item, throw an {@link IllegalArgumentException}; if it emits no items, return a default * value. *

- * + * *

*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code blockingSingle} does not operate by default on a particular {@link Scheduler}.
@@ -5986,8 +6421,8 @@ public final T blockingSingle() { * * @param defaultItem * a default value to return if this {@code Flowable} emits no items - * @return the single item emitted by this {@code Flowable}, or the default value if it emits no - * items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX documentation: First */ @CheckReturnValue @@ -6001,7 +6436,7 @@ public final T blockingSingle(@NonNull T defaultItem) { /** * Returns a {@link Future} representing the only value emitted by this {@code Flowable}. *

- * + * *

* If the {@code Flowable} emits more than one item, {@link java.util.concurrent.Future} will receive an * {@link java.lang.IndexOutOfBoundsException}. If the {@code Flowable} is empty, {@link java.util.concurrent.Future} @@ -6011,13 +6446,13 @@ public final T blockingSingle(@NonNull T defaultItem) { * If the {@code Flowable} may emit more than one item, use {@code Flowable.toList().toFuture()}. *

*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code toFuture} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code Future} that expects a single item to be emitted by this {@code Flowable} + * @return the new {@code Future} instance * @see ReactiveX documentation: To */ @CheckReturnValue @@ -6029,14 +6464,14 @@ public final Future toFuture() { } /** - * Runs the source {@code Flowable} to a terminal event, ignoring any values and rethrowing any exception. + * Runs the current {@code Flowable} to a terminal event, ignoring any values and rethrowing any exception. *

* Note that calling this method will block the caller thread until the upstream terminates * normally or with an error. Therefore, calling this method from special threads such as the * Android Main Thread or the Swing Event Dispatch Thread is not recommended. *

*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
@@ -6066,12 +6501,13 @@ public final void blockingSubscribe() { * Android Main Thread or the Swing Event Dispatch Thread is not recommended. *
*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
*
* @param onNext the callback action for each source value + * @throws NullPointerException if {@code onNext} is {@code null} * @since 2.0 * @see #blockingSubscribe(Consumer, Consumer) * @see #blockingSubscribe(Consumer, Consumer, Action) @@ -6096,7 +6532,7 @@ public final void blockingSubscribe(@NonNull Consumer onNext) { * Android Main Thread or the Swing Event Dispatch Thread is not recommended. *
*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an bounded manner (up to bufferSize + *
The operator consumes the current {@code Flowable} in an bounded manner (up to bufferSize * outstanding request amount for items).
*
Scheduler:
*
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
@@ -6104,6 +6540,8 @@ public final void blockingSubscribe(@NonNull Consumer onNext) { *

History: 2.1.15 - experimental * @param onNext the callback action for each source value * @param bufferSize the size of the buffer + * @throws NullPointerException if {@code onNext} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see #blockingSubscribe(Consumer, Consumer) * @see #blockingSubscribe(Consumer, Consumer, Action) * @since 2.2 @@ -6122,13 +6560,14 @@ public final void blockingSubscribe(@NonNull Consumer onNext, int buf * Android Main Thread or the Swing Event Dispatch Thread is not recommended. *

*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
*
* @param onNext the callback action for each source value * @param onError the callback action for an error event + * @throws NullPointerException if {@code onNext} or {@code onError} is {@code null} * @since 2.0 * @see #blockingSubscribe(Consumer, Consumer, Action) */ @@ -6146,7 +6585,7 @@ public final void blockingSubscribe(@NonNull Consumer onNext, @NonNul * Android Main Thread or the Swing Event Dispatch Thread is not recommended. *
*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an bounded manner (up to bufferSize + *
The operator consumes the current {@code Flowable} in an bounded manner (up to bufferSize * outstanding request amount for items).
*
Scheduler:
*
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
@@ -6155,6 +6594,8 @@ public final void blockingSubscribe(@NonNull Consumer onNext, @NonNul * @param onNext the callback action for each source value * @param onError the callback action for an error event * @param bufferSize the size of the buffer + * @throws NullPointerException if {@code onNext} or {@code onError} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @since 2.2 * @see #blockingSubscribe(Consumer, Consumer, Action) */ @@ -6173,7 +6614,7 @@ public final void blockingSubscribe(@NonNull Consumer onNext, @NonNul * Android Main Thread or the Swing Event Dispatch Thread is not recommended. *
*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an unbounded manner + *
The operator consumes the current {@code Flowable} in an unbounded manner * (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
@@ -6181,6 +6622,7 @@ public final void blockingSubscribe(@NonNull Consumer onNext, @NonNul * @param onNext the callback action for each source value * @param onError the callback action for an error event * @param onComplete the callback action for the completion event. + * @throws NullPointerException if {@code onNext}, {@code onError} or {@code onComplete} is {@code null} * @since 2.0 */ @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @@ -6197,7 +6639,7 @@ public final void blockingSubscribe(@NonNull Consumer onNext, @NonNul * Android Main Thread or the Swing Event Dispatch Thread is not recommended. *
*
Backpressure:
- *
The operator consumes the source {@code Flowable} in an bounded manner (up to bufferSize + *
The operator consumes the current {@code Flowable} in an bounded manner (up to bufferSize * outstanding request amount for items).
*
Scheduler:
*
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
@@ -6207,12 +6649,14 @@ public final void blockingSubscribe(@NonNull Consumer onNext, @NonNul * @param onError the callback action for an error event * @param onComplete the callback action for the completion event. * @param bufferSize the size of the buffer + * @throws NullPointerException if {@code onNext}, {@code onError} or {@code onComplete} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @since 2.2 */ @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) public final void blockingSubscribe(@NonNull Consumer onNext, @NonNull Consumer onError, @NonNull Action onComplete, - int bufferSize) { + int bufferSize) { FlowableBlockingSubscribe.subscribe(this, onNext, onError, onComplete, bufferSize); } @@ -6232,25 +6676,27 @@ public final void blockingSubscribe(@NonNull Consumer onNext, @NonNul *
* The cancellation and backpressure is composed through. * @param subscriber the subscriber to forward events and calls to in the current thread + * @throws NullPointerException if {@code subscriber} is {@code null} * @since 2.0 */ @BackpressureSupport(BackpressureKind.SPECIAL) @SchedulerSupport(SchedulerSupport.NONE) public final void blockingSubscribe(@NonNull Subscriber subscriber) { + Objects.requireNonNull(subscriber, "subscriber is null"); FlowableBlockingSubscribe.subscribe(this, subscriber); } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping buffers, each containing {@code count} items. When the source - * {@code Publisher} completes, the resulting {@code Publisher} emits the current buffer and propagates the notification from the - * source {@code Publisher}. Note that if the source {@code Publisher} issues an {@code onError} notification the event is passed on + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping buffers, each containing {@code count} items. When the current + * {@code Flowable} completes, the resulting {@code Flowable} emits the current buffer and propagates the notification from the + * current {@code Flowable}. Note that if the current {@code Flowable} issues an {@code onError} notification the event is passed on * immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and expects the source {@code Publisher} to honor it as + *
The operator honors backpressure from downstream and expects the current {@code Flowable} to honor it as * well, although not enforced; violation may lead to {@link MissingBackpressureException} somewhere * downstream.
*
Scheduler:
@@ -6259,8 +6705,8 @@ public final void blockingSubscribe(@NonNull Subscriber subscriber) { * * @param count * the maximum number of items in each buffer before it should be emitted - * @return a {@code Flowable} that emits connected, non-overlapping buffers, each containing at most - * {@code count} items from the source {@code Publisher} + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -6272,16 +6718,16 @@ public final Flowable> buffer(int count) { } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits buffers every {@code skip} items, each containing {@code count} items. When the source - * {@code Publisher} completes, the resulting {@code Publisher} emits the current buffer and propagates the notification from the - * source {@code Publisher}. Note that if the source {@code Publisher} issues an {@code onError} notification the event is passed on + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits buffers every {@code skip} items, each containing {@code count} items. When the current + * {@code Flowable} completes, the resulting {@code Flowable} emits the current buffer and propagates the notification from the + * current {@code Flowable}. Note that if the current {@code Flowable} issues an {@code onError} notification the event is passed on * immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and expects the source {@code Publisher} to honor it as + *
The operator honors backpressure from downstream and expects the current {@code Flowable} to honor it as * well, although not enforced; violation may lead to {@link MissingBackpressureException} somewhere * downstream.
*
Scheduler:
@@ -6291,11 +6737,11 @@ public final Flowable> buffer(int count) { * @param count * the maximum size of each buffer before it should be emitted * @param skip - * how many items emitted by the source {@code Publisher} should be skipped before starting a new + * how many items emitted by the current {@code Flowable} should be skipped before starting a new * buffer. Note that when {@code skip} and {@code count} are equal, this is the same operation as * {@link #buffer(int)}. - * @return a {@code Flowable} that emits buffers for every {@code skip} item from the source {@code Publisher} and - * containing at most {@code count} items + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code count} or {@code skip} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -6307,16 +6753,16 @@ public final Flowable> buffer(int count, int skip) { } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits buffers every {@code skip} items, each containing {@code count} items. When the source - * {@code Publisher} completes, the resulting {@code Publisher} emits the current buffer and propagates the notification from the - * source {@code Publisher}. Note that if the source {@code Publisher} issues an {@code onError} notification the event is passed on + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits buffers every {@code skip} items, each containing {@code count} items. When the current + * {@code Flowable} completes, the resulting {@code Flowable} emits the current buffer and propagates the notification from the + * current {@code Flowable}. Note that if the current {@code Flowable} issues an {@code onError} notification the event is passed on * immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and expects the source {@code Publisher} to honor it as + *
The operator honors backpressure from downstream and expects the current {@code Flowable} to honor it as * well, although not enforced; violation may lead to {@link MissingBackpressureException} somewhere * downstream.
*
Scheduler:
@@ -6327,21 +6773,22 @@ public final Flowable> buffer(int count, int skip) { * @param count * the maximum size of each buffer before it should be emitted * @param skip - * how many items emitted by the source {@code Publisher} should be skipped before starting a new + * how many items emitted by the current {@code Flowable} should be skipped before starting a new * buffer. Note that when {@code skip} and {@code count} are equal, this is the same operation as * {@link #buffer(int)}. * @param bufferSupplier * a factory function that returns an instance of the collection subclass to be used and returned * as the buffer - * @return a {@code Flowable} that emits buffers for every {@code skip} item from the source {@code Publisher} and - * containing at most {@code count} items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code bufferSupplier} is {@code null} + * @throws IllegalArgumentException if {@code count} or {@code skip} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final > Flowable buffer(int count, int skip, @NonNull Supplier bufferSupplier) { + public final <@NonNull U extends Collection> Flowable buffer(int count, int skip, @NonNull Supplier bufferSupplier) { ObjectHelper.verifyPositive(count, "count"); ObjectHelper.verifyPositive(skip, "skip"); Objects.requireNonNull(bufferSupplier, "bufferSupplier is null"); @@ -6349,16 +6796,16 @@ public final > Flowable buffer(int count, int } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping buffers, each containing {@code count} items. When the source - * {@code Publisher} completes, the resulting {@code Publisher} emits the current buffer and propagates the notification from the - * source {@code Publisher}. Note that if the source {@code Publisher} issues an {@code onError} notification the event is passed on + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping buffers, each containing {@code count} items. When the current + * {@code Flowable} completes, the resulting {@code Flowable} emits the current buffer and propagates the notification from the + * current {@code Flowable}. Note that if the current {@code Flowable} issues an {@code onError} notification the event is passed on * immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and expects the source {@code Publisher} to honor it as + *
The operator honors backpressure from downstream and expects the current {@code Flowable} to honor it as * well, although not enforced; violation may lead to {@link MissingBackpressureException} somewhere * downstream.
*
Scheduler:
@@ -6371,27 +6818,28 @@ public final > Flowable buffer(int count, int * @param bufferSupplier * a factory function that returns an instance of the collection subclass to be used and returned * as the buffer - * @return a {@code Flowable} that emits connected, non-overlapping buffers, each containing at most - * {@code count} items from the source {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code bufferSupplier} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final > Flowable buffer(int count, @NonNull Supplier bufferSupplier) { + public final <@NonNull U extends Collection> Flowable buffer(int count, @NonNull Supplier bufferSupplier) { return buffer(count, count, bufferSupplier); } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} starts a new buffer periodically, as determined by the {@code timeskip} argument. It emits - * each buffer after a fixed timespan, specified by the {@code timespan} argument. When the source - * {@code Publisher} completes, the resulting {@code Publisher} emits the current buffer and propagates the notification from the - * source {@code Publisher}. Note that if the source {@code Publisher} issues an {@code onError} notification the event is passed on + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} starts a new buffer periodically, as determined by the {@code timeskip} argument. It emits + * each buffer after a fixed timespan, specified by the {@code timespan} argument. When the current + * {@code Flowable} completes, the resulting {@code Flowable} emits the current buffer and propagates the notification from the + * current {@code Flowable}. Note that if the current {@code Flowable} issues an {@code onError} notification the event is passed on * immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time. It requests {@link Long#MAX_VALUE} @@ -6406,8 +6854,8 @@ public final > Flowable buffer(int count, @No * the period of time after which a new buffer will be created * @param unit * the unit of time that applies to the {@code timespan} and {@code timeskip} arguments - * @return a {@code Flowable} that emits new buffers of items emitted by the source {@code Publisher} periodically after - * a fixed timespan has elapsed + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -6419,15 +6867,15 @@ public final Flowable> buffer(long timespan, long timeskip, @NonNull Tim } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} starts a new buffer periodically, as determined by the {@code timeskip} argument, and on the + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} starts a new buffer periodically, as determined by the {@code timeskip} argument, and on the * specified {@code scheduler}. It emits each buffer after a fixed timespan, specified by the - * {@code timespan} argument. When the source {@code Publisher} completes, the resulting {@code Publisher} emits the current buffer - * and propagates the notification from the source {@code Publisher}. Note that if the source {@code Publisher} issues an {@code onError} + * {@code timespan} argument. When the current {@code Flowable} completes, the resulting {@code Flowable} emits the current buffer + * and propagates the notification from the current {@code Flowable}. Note that if the current {@code Flowable} issues an {@code onError} * notification the event is passed on immediately without first emitting the buffer it is in the process of * assembling. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time. It requests {@link Long#MAX_VALUE} @@ -6444,8 +6892,8 @@ public final Flowable> buffer(long timespan, long timeskip, @NonNull Tim * the unit of time that applies to the {@code timespan} and {@code timeskip} arguments * @param scheduler * the {@code Scheduler} to use when determining the end and start of a buffer - * @return a {@code Flowable} that emits new buffers of items emitted by the source {@code Publisher} periodically after - * a fixed timespan has elapsed + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -6457,15 +6905,15 @@ public final Flowable> buffer(long timespan, long timeskip, @NonNull Tim } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} starts a new buffer periodically, as determined by the {@code timeskip} argument, and on the + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} starts a new buffer periodically, as determined by the {@code timeskip} argument, and on the * specified {@code scheduler}. It emits each buffer after a fixed timespan, specified by the - * {@code timespan} argument. When the source {@code Publisher} completes, the resulting {@code Publisher} emits the current buffer - * and propagates the notification from the source {@code Publisher}. Note that if the source {@code Publisher} issues an {@code onError} + * {@code timespan} argument. When the current {@code Flowable} completes, the resulting {@code Flowable} emits the current buffer + * and propagates the notification from the current {@code Flowable}. Note that if the current {@code Flowable} issues an {@code onError} * notification the event is passed on immediately without first emitting the buffer it is in the process of * assembling. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time. It requests {@link Long#MAX_VALUE} @@ -6486,15 +6934,15 @@ public final Flowable> buffer(long timespan, long timeskip, @NonNull Tim * @param bufferSupplier * a factory function that returns an instance of the collection subclass to be used and returned * as the buffer - * @return a {@code Flowable} that emits new buffers of items emitted by the source {@code Publisher} periodically after - * a fixed timespan has elapsed + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code bufferSupplier} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.CUSTOM) - public final > Flowable buffer(long timespan, long timeskip, @NonNull TimeUnit unit, + public final <@NonNull U extends Collection> Flowable buffer(long timespan, long timeskip, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Supplier bufferSupplier) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); @@ -6503,14 +6951,14 @@ public final > Flowable buffer(long timespan, } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping buffers, each of a fixed duration specified by the - * {@code timespan} argument. When the source {@code Publisher} completes, the resulting {@code Publisher} emits the current buffer - * and propagates the notification from the source {@code Publisher}. Note that if the source {@code Publisher} issues an {@code onError} + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping buffers, each of a fixed duration specified by the + * {@code timespan} argument. When the current {@code Flowable} completes, the resulting {@code Flowable} emits the current buffer + * and propagates the notification from the current {@code Flowable}. Note that if the current {@code Flowable} issues an {@code onError} * notification the event is passed on immediately without first emitting the buffer it is in the process of * assembling. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time. It requests {@link Long#MAX_VALUE} @@ -6524,8 +6972,8 @@ public final > Flowable buffer(long timespan, * buffer * @param unit * the unit of time that applies to the {@code timespan} argument - * @return a {@code Flowable} that emits connected, non-overlapping buffers of items emitted by the source - * {@code Publisher} within a fixed duration + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -6537,14 +6985,14 @@ public final Flowable> buffer(long timespan, @NonNull TimeUnit unit) { } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping buffers, each of a fixed duration specified by the + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping buffers, each of a fixed duration specified by the * {@code timespan} argument or a maximum size specified by the {@code count} argument (whichever is reached - * first). When the source {@code Publisher} completes, the resulting {@code Publisher} emits the current buffer and propagates the - * notification from the source {@code Publisher}. Note that if the source {@code Publisher} issues an {@code onError} notification the event + * first). When the current {@code Flowable} completes, the resulting {@code Flowable} emits the current buffer and propagates the + * notification from the current {@code Flowable}. Note that if the current {@code Flowable} issues an {@code onError} notification the event * is passed on immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time. It requests {@link Long#MAX_VALUE} @@ -6560,9 +7008,9 @@ public final Flowable> buffer(long timespan, @NonNull TimeUnit unit) { * the unit of time which applies to the {@code timespan} argument * @param count * the maximum size of each buffer before it is emitted - * @return a {@code Flowable} that emits connected, non-overlapping buffers of items emitted by the source - * {@code Publisher}, after a fixed duration or when the buffer reaches maximum capacity (whichever occurs - * first) + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -6574,15 +7022,15 @@ public final Flowable> buffer(long timespan, @NonNull TimeUnit unit, int } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping buffers, each of a fixed duration specified by the + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping buffers, each of a fixed duration specified by the * {@code timespan} argument as measured on the specified {@code scheduler}, or a maximum size specified by - * the {@code count} argument (whichever is reached first). When the source {@code Publisher} completes, the resulting - * {@code Publisher} emits the current buffer and propagates the notification from the source {@code Publisher}. Note that if the - * source {@code Publisher} issues an {@code onError} notification the event is passed on immediately without first emitting the + * the {@code count} argument (whichever is reached first). When the current {@code Flowable} completes, the resulting + * {@code Flowable} emits the current buffer and propagates the notification from the current {@code Flowable}. Note that if the + * current {@code Flowable} issues an {@code onError} notification the event is passed on immediately without first emitting the * buffer it is in the process of assembling. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time. It requests {@link Long#MAX_VALUE} @@ -6600,9 +7048,9 @@ public final Flowable> buffer(long timespan, @NonNull TimeUnit unit, int * the {@code Scheduler} to use when determining the end and start of a buffer * @param count * the maximum size of each buffer before it is emitted - * @return a {@code Flowable} that emits connected, non-overlapping buffers of items emitted by the source - * {@code Publisher} after a fixed duration or when the buffer reaches maximum capacity (whichever occurs - * first) + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -6614,15 +7062,15 @@ public final Flowable> buffer(long timespan, @NonNull TimeUnit unit, @No } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping buffers, each of a fixed duration specified by the + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping buffers, each of a fixed duration specified by the * {@code timespan} argument as measured on the specified {@code scheduler}, or a maximum size specified by - * the {@code count} argument (whichever is reached first). When the source {@code Publisher} completes, the resulting - * {@code Publisher} emits the current buffer and propagates the notification from the source {@code Publisher}. Note that if the - * source {@code Publisher} issues an {@code onError} notification the event is passed on immediately without first emitting the + * the {@code count} argument (whichever is reached first). When the current {@code Flowable} completes, the resulting + * {@code Flowable} emits the current buffer and propagates the notification from the current {@code Flowable}. Note that if the + * current {@code Flowable} issues an {@code onError} notification the event is passed on immediately without first emitting the * buffer it is in the process of assembling. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time. It requests {@link Long#MAX_VALUE} @@ -6646,16 +7094,16 @@ public final Flowable> buffer(long timespan, @NonNull TimeUnit unit, @No * as the buffer * @param restartTimerOnMaxSize if {@code true}, the time window is restarted when the max capacity of the current buffer * is reached - * @return a {@code Flowable} that emits connected, non-overlapping buffers of items emitted by the source - * {@code Publisher} after a fixed duration or when the buffer reaches maximum capacity (whichever occurs - * first) + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code bufferSupplier} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final > Flowable buffer( + public final <@NonNull U extends Collection> Flowable buffer( long timespan, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, int count, @NonNull Supplier bufferSupplier, @@ -6668,14 +7116,14 @@ public final > Flowable buffer( } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping buffers, each of a fixed duration specified by the - * {@code timespan} argument and on the specified {@code scheduler}. When the source {@code Publisher} completes, the - * resulting {@code Publisher} emits the current buffer and propagates the notification from the source {@code Publisher}. Note that - * if the source {@code Publisher} issues an {@code onError} notification the event is passed on immediately without first emitting + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping buffers, each of a fixed duration specified by the + * {@code timespan} argument and on the specified {@code scheduler}. When the current {@code Flowable} completes, the + * resulting {@code Flowable} emits the current buffer and propagates the notification from the current {@code Flowable}. Note that + * if the current {@code Flowable} issues an {@code onError} notification the event is passed on immediately without first emitting * the buffer it is in the process of assembling. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time. It requests {@link Long#MAX_VALUE} @@ -6691,8 +7139,8 @@ public final > Flowable buffer( * the unit of time which applies to the {@code timespan} argument * @param scheduler * the {@code Scheduler} to use when determining the end and start of a buffer - * @return a {@code Flowable} that emits connected, non-overlapping buffers of items emitted by the source - * {@code Publisher} within a fixed duration + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -6704,13 +7152,13 @@ public final Flowable> buffer(long timespan, @NonNull TimeUnit unit, @No } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits buffers that it creates when the specified {@code openingIndicator} {@code Publisher} emits an - * item, and closes when the {@code Publisher} returned from {@code closingIndicator} emits an item. If any of the source - * {@code Publisher}, {@code openingIndicator} or {@code closingIndicator} issues an {@code onError} notification the event is passed + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits buffers that it creates when the specified {@code openingIndicator} {@link Publisher} emits an + * item, and closes when the {@code Publisher} returned from {@code closingIndicator} emits an item. If any of the current + * {@code PFlowable}, {@code openingIndicator} or {@code closingIndicator} issues an {@code onError} notification the event is passed * on immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it is instead controlled by the given {@code Publisher}s and @@ -6726,28 +7174,28 @@ public final Flowable> buffer(long timespan, @NonNull TimeUnit unit, @No * @param closingIndicator * the {@link Function} that is used to produce a {@code Publisher} for every buffer created. When this * {@code Publisher} emits an item, the associated buffer is emitted. - * @return a {@code Flowable} that emits buffers, containing items from the source {@code Publisher}, that are created - * and closed when the specified {@code Publisher}s emit items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code openingIndicator} or {@code closingIndicator} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable> buffer( - @NonNull Flowable openingIndicator, - @NonNull Function> closingIndicator) { + public final <@NonNull TOpening, @NonNull TClosing> Flowable> buffer( + @NonNull Publisher openingIndicator, + @NonNull Function> closingIndicator) { return buffer(openingIndicator, closingIndicator, ArrayListSupplier.asSupplier()); } /** - * Returns a {@code Flowable} that emits buffers of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits buffers that it creates when the specified {@code openingIndicator} {@code Publisher} emits an - * item, and closes when the {@code Publisher} returned from {@code closingIndicator} emits an item. If any of the source - * {@code Publisher}, {@code openingIndicator} or {@code closingIndicator} issues an {@code onError} notification the event is passed + * Returns a {@code Flowable} that emits buffers of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits buffers that it creates when the specified {@code openingIndicator} {@link Publisher} emits an + * item, and closes when the {@code Publisher} returned from {@code closingIndicator} emits an item. If any of the current + * {@code Flowable}, {@code openingIndicator} or {@code closingIndicator} issues an {@code onError} notification the event is passed * on immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it is instead controlled by the given {@code Publisher}s and @@ -6767,17 +7215,17 @@ public final Flowable> buffer( * @param bufferSupplier * a factory function that returns an instance of the collection subclass to be used and returned * as the buffer - * @return a {@code Flowable} that emits buffers, containing items from the source {@code Publisher}, that are created - * and closed when the specified {@code Publisher}s emit items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code openingIndicator}, {@code closingIndicator} or {@code bufferSupplier} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final > Flowable buffer( - @NonNull Flowable openingIndicator, - @NonNull Function> closingIndicator, + public final <@NonNull TOpening, @NonNull TClosing, @NonNull U extends Collection> Flowable buffer( + @NonNull Publisher openingIndicator, + @NonNull Function> closingIndicator, @NonNull Supplier bufferSupplier) { Objects.requireNonNull(openingIndicator, "openingIndicator is null"); Objects.requireNonNull(closingIndicator, "closingIndicator is null"); @@ -6786,13 +7234,13 @@ public final > Flowable b } /** - * Returns a {@code Flowable} that emits non-overlapping buffered items from the source {@link Publisher} each time the - * specified boundary {@code Publisher} emits an item. + * Returns a {@code Flowable} that emits non-overlapping buffered items from the current {@code Flowable} each time the + * specified boundary {@link Publisher} emits an item. *

- * + * *

* Completion of either the source or the boundary {@code Publisher} causes the returned {@code Publisher} to emit the - * latest buffer and complete. If either the source {@code Publisher} or the boundary {@code Publisher} issues an {@code onError} notification + * latest buffer and complete. If either the current {@code Flowable} or the boundary {@code Publisher} issues an {@code onError} notification * the event is passed on immediately without first emitting the buffer it is in the process of assembling. *

*
Backpressure:
@@ -6807,8 +7255,8 @@ public final > Flowable b * the boundary value type (ignored) * @param boundaryIndicator * the boundary {@code Publisher} - * @return a {@code Flowable} that emits buffered items from the source {@code Publisher} when the boundary {@code Publisher} - * emits an item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code boundaryIndicator} is {@code null} * @see #buffer(Publisher, int) * @see ReactiveX operators documentation: Buffer */ @@ -6816,18 +7264,18 @@ public final > Flowable b @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable> buffer(@NonNull Publisher boundaryIndicator) { + public final <@NonNull B> Flowable> buffer(@NonNull Publisher boundaryIndicator) { return buffer(boundaryIndicator, ArrayListSupplier.asSupplier()); } /** - * Returns a {@code Flowable} that emits non-overlapping buffered items from the source {@link Publisher} each time the - * specified boundary {@code Publisher} emits an item. + * Returns a {@code Flowable} that emits non-overlapping buffered items from the current {@code Flowable} each time the + * specified boundary {@link Publisher} emits an item. *

- * + * *

* Completion of either the source or the boundary {@code Publisher} causes the returned {@code Publisher} to emit the - * latest buffer and complete. If either the source {@code Publisher} or the boundary {@code Publisher} issues an {@code onError} notification + * latest buffer and complete. If either the current {@code Flowable} or the boundary {@code Publisher} issues an {@code onError} notification * the event is passed on immediately without first emitting the buffer it is in the process of assembling. *

*
Backpressure:
@@ -6844,8 +7292,9 @@ public final Flowable> buffer(@NonNull Publisher boundaryIndicato * the boundary {@code Publisher} * @param initialCapacity * the initial capacity of each buffer chunk - * @return a {@code Flowable} that emits buffered items from the source {@code Publisher} when the boundary {@code Publisher} - * emits an item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code boundaryIndicator} is {@code null} + * @throws IllegalArgumentException if {@code initialCapacity} is non-positive * @see ReactiveX operators documentation: Buffer * @see #buffer(Publisher) */ @@ -6853,19 +7302,19 @@ public final Flowable> buffer(@NonNull Publisher boundaryIndicato @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable> buffer(@NonNull Publisher boundaryIndicator, int initialCapacity) { + public final <@NonNull B> Flowable> buffer(@NonNull Publisher boundaryIndicator, int initialCapacity) { ObjectHelper.verifyPositive(initialCapacity, "initialCapacity"); return buffer(boundaryIndicator, Functions.createArrayList(initialCapacity)); } /** - * Returns a {@code Flowable} that emits non-overlapping buffered items from the source {@link Publisher} each time the - * specified boundary {@code Publisher} emits an item. + * Returns a {@code Flowable} that emits non-overlapping buffered items from the current {@code Flowable} each time the + * specified boundary {@link Publisher} emits an item. *

- * + * *

* Completion of either the source or the boundary {@code Publisher} causes the returned {@code Publisher} to emit the - * latest buffer and complete. If either the source {@code Publisher} or the boundary {@code Publisher} issues an {@code onError} notification + * latest buffer and complete. If either the current {@code Flowable} or the boundary {@code Publisher} issues an {@code onError} notification * the event is passed on immediately without first emitting the buffer it is in the process of assembling. *

*
Backpressure:
@@ -6884,8 +7333,8 @@ public final Flowable> buffer(@NonNull Publisher boundaryIndicato * @param bufferSupplier * a factory function that returns an instance of the collection subclass to be used and returned * as the buffer - * @return a {@code Flowable} that emits buffered items from the source {@code Publisher} when the boundary {@code Publisher} - * emits an item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code boundaryIndicator} or {@code bufferSupplier} is {@code null} * @see #buffer(Publisher, int) * @see ReactiveX operators documentation: Buffer */ @@ -6893,7 +7342,7 @@ public final Flowable> buffer(@NonNull Publisher boundaryIndicato @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final > Flowable buffer(@NonNull Publisher boundaryIndicator, @NonNull Supplier bufferSupplier) { + public final <@NonNull B, @NonNull U extends Collection> Flowable buffer(@NonNull Publisher boundaryIndicator, @NonNull Supplier bufferSupplier) { Objects.requireNonNull(boundaryIndicator, "boundaryIndicator is null"); Objects.requireNonNull(bufferSupplier, "bufferSupplier is null"); return RxJavaPlugins.onAssembly(new FlowableBufferExactBoundary<>(this, boundaryIndicator, bufferSupplier)); @@ -6903,7 +7352,7 @@ public final > Flowable buffer(@NonNull Pu * Returns a {@code Flowable} that subscribes to this {@link Publisher} lazily, caches all of its events * and replays them, in the same order as received, to all the downstream subscribers. *

- * + * *

* This is useful when you want a {@code Publisher} to cache responses and you can't control the * subscribe/cancel behavior of all the {@link Subscriber}s. @@ -6913,7 +7362,7 @@ public final > Flowable buffer(@NonNull Pu * that return a {@link ConnectableFlowable} require an explicit call to {@link ConnectableFlowable#connect()}. *

* Note: You sacrifice the ability to cancel the origin when you use the {@code cache} - * {@code Subscriber} so be careful not to use this {@code Subscriber} on {@code Publisher}s that emit an infinite or very large number + * operator so be careful not to use this operator on {@code Publisher}s that emit an infinite or very large number * of items that will use up memory. * A possible workaround is to apply {@link #takeUntil(Publisher)} with a predicate or * another source before (and perhaps after) the application of {@code cache()}. @@ -6946,9 +7395,10 @@ public final > Flowable buffer(@NonNull Pu *

{@code cache} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code Flowable} that, when first subscribed to, caches all of its items and notifications for the - * benefit of subsequent subscribers + * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: Replay + * @see #takeUntil(Predicate) + * @see #takeUntil(Publisher) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @@ -6962,7 +7412,7 @@ public final Flowable cache() { * Returns a {@code Flowable} that subscribes to this {@link Publisher} lazily, caches all of its events * and replays them, in the same order as received, to all the downstream subscribers. *

- * + * *

* This is useful when you want a {@code Publisher} to cache responses and you can't control the * subscribe/cancel behavior of all the {@link Subscriber}s. @@ -6972,7 +7422,7 @@ public final Flowable cache() { * that return a {@link ConnectableFlowable} require an explicit call to {@link ConnectableFlowable#connect()}. *

* Note: You sacrifice the ability to cancel the origin when you use the {@code cache} - * {@code Subscriber} so be careful not to use this {@code Subscriber} on {@code Publisher}s that emit an infinite or very large number + * operator so be careful not to use this operator on {@code Publisher}s that emit an infinite or very large number * of items that will use up memory. * A possible workaround is to apply {@link #takeUntil(Publisher)} with a predicate or * another source before (and perhaps after) the application of {@code cacheWithInitialCapacity()}. @@ -7009,9 +7459,11 @@ public final Flowable cache() { * {@link #replay(int)} in combination with {@link ConnectableFlowable#autoConnect()} or similar. * * @param initialCapacity hint for number of items to cache (for optimizing underlying data structure) - * @return a {@code Flowable} that, when first subscribed to, caches all of its items and notifications for the - * benefit of subsequent subscribers + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code initialCapacity} is non-positive * @see ReactiveX operators documentation: Replay + * @see #takeUntil(Predicate) + * @see #takeUntil(Publisher) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @@ -7023,13 +7475,15 @@ public final Flowable cacheWithInitialCapacity(int initialCapacity) { } /** - * Returns a {@code Flowable} that emits the items emitted by the source {@link Publisher}, converted to the specified - * type. + * Returns a {@code Flowable} that emits the upstream items while + * they can be cast via {@link Class#cast(Object)} until the upstream terminates, + * or until the upstream signals an item which can't be cast, + * resulting in a {@link ClassCastException} to be signaled to the downstream. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code cast} does not operate by default on a particular {@link Scheduler}.
@@ -7037,17 +7491,16 @@ public final Flowable cacheWithInitialCapacity(int initialCapacity) { * * @param the output value type cast to * @param clazz - * the target class type that {@code cast} will cast the items emitted by the source {@code Publisher} - * into before emitting them from the resulting {@code Publisher} - * @return a {@code Flowable} that emits each item from the source {@code Publisher} after converting it to the - * specified type + * the target class to use to try and cast the upstream items into + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code clazz} is {@code null} * @see ReactiveX operators documentation: Map */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable cast(@NonNull Class clazz) { + public final <@NonNull U> Flowable cast(@NonNull Class clazz) { Objects.requireNonNull(clazz, "clazz is null"); return map(Functions.castFunction(clazz)); } @@ -7056,7 +7509,7 @@ public final Flowable cast(@NonNull Class clazz) { * Collects items emitted by the finite source {@link Publisher} into a single mutable data structure and returns * a {@link Single} that emits this structure. *

- * + * *

* This is a simplified version of {@code reduce} that does not need to return the state on each pass. *

@@ -7077,8 +7530,8 @@ public final Flowable cast(@NonNull Class clazz) { * @param collector * a function that accepts the {@code state} and an emitted item, and modifies {@code state} * accordingly - * @return a {@code Single} that emits the result of collecting the values emitted by the source {@code Publisher} - * into a single mutable data structure + * @return the new {@code Single} instance + * @throws NullPointerException if {@code initialItemSupplier} or {@code collector} is {@code null} * @see ReactiveX operators documentation: Reduce * @see #collect(Collector) */ @@ -7086,7 +7539,7 @@ public final Flowable cast(@NonNull Class clazz) { @NonNull @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) - public final Single collect(@NonNull Supplier initialItemSupplier, @NonNull BiConsumer collector) { + public final <@NonNull U> Single collect(@NonNull Supplier initialItemSupplier, @NonNull BiConsumer collector) { Objects.requireNonNull(initialItemSupplier, "initialItemSupplier is null"); Objects.requireNonNull(collector, "collector is null"); return RxJavaPlugins.onAssembly(new FlowableCollectSingle<>(this, initialItemSupplier, collector)); @@ -7096,7 +7549,7 @@ public final Single collect(@NonNull Supplier initialItemSup * Collects items emitted by the finite source {@link Publisher} into a single mutable data structure and returns * a {@link Single} that emits this structure. *

- * + * *

* This is a simplified version of {@code reduce} that does not need to return the state on each pass. *

@@ -7117,8 +7570,8 @@ public final Single collect(@NonNull Supplier initialItemSup * @param collector * a function that accepts the {@code state} and an emitted item, and modifies {@code state} * accordingly - * @return a {@code Single} that emits the result of collecting the values emitted by the source {@code Publisher} - * into a single mutable data structure + * @return the new {@code Single} instance + * @throws NullPointerException if {@code initialItem} or {@code collector} is {@code null} * @see ReactiveX operators documentation: Reduce */ @CheckReturnValue @@ -7131,25 +7584,26 @@ public final Single collect(@NonNull Supplier initialItemSup } /** - * Transform a {@link Publisher} by applying a particular Transformer function to it. + * Transform the current {@code Flowable} by applying a particular {@link FlowableTransformer} function to it. *

- * This method operates on the {@code Publisher} itself whereas {@link #lift} operates on the {@code Publisher}'s + * This method operates on the {@code Flowable} itself whereas {@link #lift} operates on the {@code Flowable}'s * {@link Subscriber}s. *

- * If the operator you are creating is designed to act on the individual items emitted by a source - * {@code Publisher}, use {@link #lift}. If your operator is designed to transform the source {@code Publisher} as a whole + * If the operator you are creating is designed to act on the individual items emitted by a current + * {@code Flowable}, use {@link #lift}. If your operator is designed to transform the current {@code Flowable} as a whole * (for instance, by applying a particular set of existing RxJava operators to it) use {@code compose}. *

*
Backpressure:
*
The operator itself doesn't interfere with the backpressure behavior which only depends - * on what kind of {@code Publisher} the transformer returns.
+ * on what kind of {@link Publisher} the {@code FlowableTransformer} returns.
*
Scheduler:
*
{@code compose} does not operate by default on a particular {@link Scheduler}.
*
* * @param the value type of the output {@code Publisher} - * @param composer implements the function that transforms the source {@code Publisher} - * @return the source {@code Publisher}, transformed by the transformer function + * @param composer implements the function that transforms the current {@code Flowable} + * @return the new composed {@code Flowable} instance + * @throws NullPointerException if {@code composer} is {@code null} * @see RxJava wiki: Implementing Your Own Operators */ @SuppressWarnings("unchecked") @@ -7157,16 +7611,16 @@ public final Single collect(@NonNull Supplier initialItemSup @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable compose(@NonNull FlowableTransformer composer) { + public final <@NonNull R> Flowable compose(@NonNull FlowableTransformer composer) { return fromPublisher(((FlowableTransformer) Objects.requireNonNull(composer, "composer is null")).apply(this)); } /** * Returns a new {@code Flowable} that emits items resulting from applying a function that you supply to each item - * emitted by the source {@link Publisher}, where that function returns a {@code Publisher}, and then emitting the items - * that result from concatenating those resulting {@code Publisher}s. + * emitted by the current {@code Flowable}, where that function returns a {@link Publisher}, and then emitting the items + * that result from concatenating those returned {@code Publisher}s. *

- * + * *

* Note that there is no guarantee where the given {@code mapper} function will be executed; it could be on the subscribing thread, * on the upstream thread signaling the new item to be mapped or on the thread where the inner source terminates. To ensure @@ -7174,7 +7628,7 @@ public final Flowable compose(@NonNull FlowableTransformer *

Backpressure:
*
The operator honors backpressure from downstream. Both this and the inner {@code Publisher}s are - * expected to honor backpressure as well. If the source {@code Publisher} violates the rule, the operator will + * expected to honor backpressure as well. If the current {@code Flowable} violates the rule, the operator will * signal a {@link MissingBackpressureException}. If any of the inner {@code Publisher}s doesn't honor * backpressure, that may throw an {@link IllegalStateException} when that * {@code Publisher} completes.
@@ -7184,26 +7638,26 @@ public final Flowable compose(@NonNull FlowableTransformer the type of the inner {@code Publisher} sources and thus the output type * @param mapper - * a function that, when applied to an item emitted by the source {@code Publisher}, returns a + * a function that, when applied to an item emitted by the current {@code Flowable}, returns a * {@code Publisher} - * @return a {@code Flowable} that emits the result of applying the transformation function to each item emitted - * by the source {@code Publisher} and concatenating the {@code Publisher}s obtained from this transformation + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable concatMap(@NonNull Function> mapper) { + public final <@NonNull R> Flowable concatMap(@NonNull Function> mapper) { return concatMap(mapper, 2); } /** * Returns a new {@code Flowable} that emits items resulting from applying a function that you supply to each item - * emitted by the source {@link Publisher}, where that function returns a {@code Publisher}, and then emitting the items - * that result from concatenating those resulting {@code Publisher}s. + * emitted by the current {@code Flowable}, where that function returns a {@link Publisher}, and then emitting the items + * that result from concatenating those returned {@code Publisher}s. *

- * + * *

* Note that there is no guarantee where the given {@code mapper} function will be executed; it could be on the subscribing thread, * on the upstream thread signaling the new item to be mapped or on the thread where the inner source terminates. To ensure @@ -7211,7 +7665,7 @@ public final Flowable concatMap(@NonNull Function *

Backpressure:
*
The operator honors backpressure from downstream. Both this and the inner {@code Publisher}s are - * expected to honor backpressure as well. If the source {@code Publisher} violates the rule, the operator will + * expected to honor backpressure as well. If the current {@code Flowable} violates the rule, the operator will * signal a {@link MissingBackpressureException}. If any of the inner {@code Publisher}s doesn't honor * backpressure, that may throw an {@link IllegalStateException} when that * {@code Publisher} completes.
@@ -7221,12 +7675,13 @@ public final Flowable concatMap(@NonNull Function the type of the inner {@code Publisher} sources and thus the output type * @param mapper - * a function that, when applied to an item emitted by the source {@code Publisher}, returns a + * a function that, when applied to an item emitted by the current {@code Flowable}, returns a * {@code Publisher} * @param prefetch * the number of elements to prefetch from the current {@code Flowable} - * @return a {@code Flowable} that emits the result of applying the transformation function to each item emitted - * by the source {@code Publisher} and concatenating the {@code Publisher}s obtained from this transformation + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive * @see ReactiveX operators documentation: FlatMap * @see #concatMap(Function, int, Scheduler) */ @@ -7234,7 +7689,7 @@ public final Flowable concatMap(@NonNull Function Flowable concatMap(@NonNull Function> mapper, int prefetch) { + public final <@NonNull R> Flowable concatMap(@NonNull Function> mapper, int prefetch) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); if (this instanceof ScalarSupplier) { @@ -7250,17 +7705,17 @@ public final Flowable concatMap(@NonNull Function - * + * *

* The difference between {@link #concatMap(Function, int)} and this operator is that this operator guarantees the {@code mapper} * function is executed on the specified scheduler. *

*
Backpressure:
*
The operator honors backpressure from downstream. Both this and the inner {@code Publisher}s are - * expected to honor backpressure as well. If the source {@code Publisher} violates the rule, the operator will + * expected to honor backpressure as well. If the current {@code Flowable} violates the rule, the operator will * signal a {@link MissingBackpressureException}. If any of the inner {@code Publisher}s doesn't honor * backpressure, that may throw an {@link IllegalStateException} when that * {@code Publisher} completes.
@@ -7270,14 +7725,15 @@ public final Flowable concatMap(@NonNull Function the type of the inner {@code Publisher} sources and thus the output type * @param mapper - * a function that, when applied to an item emitted by the source {@code Publisher}, returns a + * a function that, when applied to an item emitted by the current {@code Flowable}, returns a * {@code Publisher} * @param prefetch * the number of elements to prefetch from the current {@code Flowable} * @param scheduler * the scheduler where the {@code mapper} function will be executed - * @return a {@code Flowable} that emits the result of applying the transformation function to each item emitted - * by the source {@code Publisher} and concatenating the {@code Publisher}s obtained from this transformation + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 3.0.0 * @see #concatMap(Function, int) @@ -7287,10 +7743,10 @@ public final Flowable concatMap(@NonNull Function Flowable concatMap(@NonNull Function> mapper, int prefetch, @NonNull Scheduler scheduler) { + public final <@NonNull R> Flowable concatMap(@NonNull Function> mapper, int prefetch, @NonNull Scheduler scheduler) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); - Objects.requireNonNull(scheduler, "scheduler"); + Objects.requireNonNull(scheduler, "scheduler is null"); return RxJavaPlugins.onAssembly(new FlowableConcatMapScheduler<>(this, mapper, prefetch, ErrorMode.IMMEDIATE, scheduler)); } @@ -7298,7 +7754,7 @@ public final Flowable concatMap(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure. If this {@code Flowable} violates the rule, the operator will @@ -7310,7 +7766,8 @@ public final Flowable concatMap(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure. If this {@code Flowable} violates the rule, the operator will @@ -7342,7 +7799,9 @@ public final Completable concatMapCompletable(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure. If this {@code Flowable} violates the rule, the operator will @@ -7373,7 +7832,8 @@ public final Completable concatMapCompletable(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure. If this {@code Flowable} violates the rule, the operator will @@ -7408,7 +7868,8 @@ public final Completable concatMapCompletableDelayError(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure. If this {@code Flowable} violates the rule, the operator will @@ -7447,7 +7908,9 @@ public final Completable concatMapCompletableDelayError(@NonNull Function *
Backpressure:
*
The operator honors backpressure from downstream. Both this and the inner {@code Publisher}s are - * expected to honor backpressure as well. If the source {@code Publisher} violates the rule, the operator will + * expected to honor backpressure as well. If the current {@code Flowable} violates the rule, the operator will * signal a {@link MissingBackpressureException}. If any of the inner {@code Publisher}s doesn't honor * backpressure, that may throw an {@link IllegalStateException} when that * {@code Publisher} completes.
@@ -7483,14 +7946,15 @@ public final Completable concatMapCompletableDelayError(@NonNull Function the result value type * @param mapper the function that maps the items of this {@code Publisher} into the inner {@code Publisher}s. - * @return the new {@code Publisher} instance with the concatenation behavior + * @return the new {@code Flowable} instance with the concatenation behavior + * @throws NullPointerException if {@code mapper} is {@code null} * @see #concatMapDelayError(Function, boolean, int, Scheduler) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable concatMapDelayError(@NonNull Function> mapper) { + public final <@NonNull R> Flowable concatMapDelayError(@NonNull Function> mapper) { return concatMapDelayError(mapper, true, 2); } @@ -7507,7 +7971,7 @@ public final Flowable concatMapDelayError(@NonNull Function *
Backpressure:
*
The operator honors backpressure from downstream. Both this and the inner {@code Publisher}s are - * expected to honor backpressure as well. If the source {@code Publisher} violates the rule, the operator will + * expected to honor backpressure as well. If the current {@code Flowable} violates the rule, the operator will * signal a {@link MissingBackpressureException}. If any of the inner {@code Publisher}s doesn't honor * backpressure, that may throw an {@link IllegalStateException} when that * {@code Publisher} completes.
@@ -7519,17 +7983,19 @@ public final Flowable concatMapDelayError(@NonNull Function Flowable concatMapDelayError(@NonNull Function> mapper, + public final <@NonNull R> Flowable concatMapDelayError(@NonNull Function> mapper, boolean tillTheEnd, int prefetch) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); @@ -7556,7 +8022,7 @@ public final Flowable concatMapDelayError(@NonNull Function *
Backpressure:
*
The operator honors backpressure from downstream. Both this and the inner {@code Publisher}s are - * expected to honor backpressure as well. If the source {@code Publisher} violates the rule, the operator will + * expected to honor backpressure as well. If the current {@code Flowable} violates the rule, the operator will * signal a {@link MissingBackpressureException}. If any of the inner {@code Publisher}s doesn't honor * backpressure, that may throw an {@link IllegalStateException} when that * {@code Publisher} completes.
@@ -7568,12 +8034,14 @@ public final Flowable concatMapDelayError(@NonNull Function Flowable concatMapDelayError(@NonNull Function Flowable concatMapDelayError(@NonNull Function> mapper, + public final <@NonNull R> Flowable concatMapDelayError(@NonNull Function> mapper, boolean tillTheEnd, int prefetch, @NonNull Scheduler scheduler) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); @@ -7594,7 +8062,7 @@ public final Flowable concatMapDelayError(@NonNull Function * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them in + * inner {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them in * order, each one after the previous one completes. *
*
Backpressure:
@@ -7606,14 +8074,15 @@ public final Flowable concatMapDelayError(@NonNull Function the value type * @param mapper the function that maps a sequence of values into a sequence of {@code Publisher}s that will be * eagerly concatenated - * @return the new {@code Publisher} instance with the specified concatenation behavior + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code mapper} is {@code null} * @since 2.0 */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable concatMapEager(@NonNull Function> mapper) { + public final <@NonNull R> Flowable concatMapEager(@NonNull Function> mapper) { return concatMapEager(mapper, bufferSize(), bufferSize()); } @@ -7622,7 +8091,7 @@ public final Flowable concatMapEager(@NonNull Function * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them in + * inner {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them in * order, each one after the previous one completes. *
*
Backpressure:
@@ -7636,14 +8105,16 @@ public final Flowable concatMapEager(@NonNull Function Flowable concatMapEager(@NonNull Function> mapper, + public final <@NonNull R> Flowable concatMapEager(@NonNull Function> mapper, int maxConcurrency, int prefetch) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); @@ -7656,7 +8127,7 @@ public final Flowable concatMapEager(@NonNull Function * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them in + * inner {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them in * order, each one after the previous one completes. *
*
Backpressure:
@@ -7670,25 +8141,26 @@ public final Flowable concatMapEager(@NonNull Function Flowable concatMapEagerDelayError(@NonNull Function> mapper, + public final <@NonNull R> Flowable concatMapEagerDelayError(@NonNull Function> mapper, boolean tillTheEnd) { return concatMapEagerDelayError(mapper, tillTheEnd, bufferSize(), bufferSize()); } /** * Maps a sequence of values into {@link Publisher}s and concatenates these {@code Publisher}s eagerly into a single - * {@code Publisher}. + * {@code Flowable} sequence. *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them in + * inner {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them in * order, each one after the previous one completes. *

*
Backpressure:
@@ -7707,14 +8179,16 @@ public final Flowable concatMapEagerDelayError(@NonNull Function Flowable concatMapEagerDelayError(@NonNull Function> mapper, + public final <@NonNull R> Flowable concatMapEagerDelayError(@NonNull Function> mapper, boolean tillTheEnd, int maxConcurrency, int prefetch) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); @@ -7723,64 +8197,65 @@ public final Flowable concatMapEagerDelayError(@NonNull Function *
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s is - * expected to honor backpressure as well. If the source {@code Publisher} violates the rule, the operator will + *
The operator honors backpressure from downstream. The current {@code Flowable}s is + * expected to honor backpressure as well. If the current {@code Flowable} violates the rule, the operator will * signal a {@link MissingBackpressureException}.
*
Scheduler:
*
{@code concatMapIterable} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of item emitted by the resulting {@code Publisher} + * the type of item emitted by the resulting {@code Flowable} * @param mapper * a function that returns an {@code Iterable} sequence of values for when given an item emitted by the - * source {@code Publisher} - * @return a {@code Flowable} that emits the results of concatenating the items emitted by the source {@code Publisher} with - * the values in the {@code Iterable}s corresponding to those items, as generated by {@code collectionSelector} + * current {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable concatMapIterable(@NonNull Function> mapper) { + public final <@NonNull U> Flowable concatMapIterable(@NonNull Function> mapper) { return concatMapIterable(mapper, 2); } /** - * Returns a {@code Flowable} that concatenate each item emitted by the source {@link Publisher} with the values in an + * Returns a {@code Flowable} that concatenate each item emitted by the current {@code Flowable} with the values in an * {@link Iterable} corresponding to that item that is generated by a selector. * *
*
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s is - * expected to honor backpressure as well. If the source {@code Publisher} violates the rule, the operator will + *
The operator honors backpressure from downstream. The current {@code Flowable} is + * expected to honor backpressure as well. If the current {@code Flowable} violates the rule, the operator will * signal a {@link MissingBackpressureException}.
*
Scheduler:
*
{@code concatMapIterable} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of item emitted by the resulting {@code Publisher} + * the type of item emitted by the resulting {@code Flowable} * @param mapper * a function that returns an {@code Iterable} sequence of values for when given an item emitted by the - * source {@code Publisher} + * current {@code Flowable} * @param prefetch * the number of elements to prefetch from the current {@code Flowable} - * @return a {@code Flowable} that emits the results of concatenating the items emitted by the source {@code Publisher} with - * the values in the {@code Iterable}s corresponding to those items, as generated by {@code collectionSelector} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable concatMapIterable(@NonNull Function> mapper, int prefetch) { + public final <@NonNull U> Flowable concatMapIterable(@NonNull Function> mapper, int prefetch) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); return RxJavaPlugins.onAssembly(new FlowableFlattenIterable<>(this, mapper, prefetch)); @@ -7791,7 +8266,7 @@ public final Flowable concatMapIterable(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure and honors @@ -7805,7 +8280,8 @@ public final Flowable concatMapIterable(@NonNull Function Flowable concatMapIterable(@NonNull Function Flowable concatMapMaybe(@NonNull Function> mapper) { + public final <@NonNull R> Flowable concatMapMaybe(@NonNull Function> mapper) { return concatMapMaybe(mapper, 2); } @@ -7823,7 +8299,7 @@ public final Flowable concatMapMaybe(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure and honors @@ -7841,7 +8317,9 @@ public final Flowable concatMapMaybe(@NonNull Function Flowable concatMapMaybe(@NonNull Function Flowable concatMapMaybe(@NonNull Function> mapper, int prefetch) { + public final <@NonNull R> Flowable concatMapMaybe(@NonNull Function> mapper, int prefetch) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); return RxJavaPlugins.onAssembly(new FlowableConcatMapMaybe<>(this, mapper, ErrorMode.IMMEDIATE, prefetch)); @@ -7861,7 +8339,7 @@ public final Flowable concatMapMaybe(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure and honors @@ -7875,7 +8353,8 @@ public final Flowable concatMapMaybe(@NonNull Function Flowable concatMapMaybe(@NonNull Function Flowable concatMapMaybeDelayError(@NonNull Function> mapper) { + public final <@NonNull R> Flowable concatMapMaybeDelayError(@NonNull Function> mapper) { return concatMapMaybeDelayError(mapper, true, 2); } @@ -7893,7 +8372,7 @@ public final Flowable concatMapMaybeDelayError(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure and honors @@ -7913,7 +8392,8 @@ public final Flowable concatMapMaybeDelayError(@NonNull Function Flowable concatMapMaybeDelayError(@NonNull Function Flowable concatMapMaybeDelayError(@NonNull Function> mapper, boolean tillTheEnd) { + public final <@NonNull R> Flowable concatMapMaybeDelayError(@NonNull Function> mapper, boolean tillTheEnd) { return concatMapMaybeDelayError(mapper, tillTheEnd, 2); } @@ -7931,7 +8411,7 @@ public final Flowable concatMapMaybeDelayError(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure and honors @@ -7955,7 +8435,9 @@ public final Flowable concatMapMaybeDelayError(@NonNull Function Flowable concatMapMaybeDelayError(@NonNull Function Flowable concatMapMaybeDelayError(@NonNull Function> mapper, boolean tillTheEnd, int prefetch) { + public final <@NonNull R> Flowable concatMapMaybeDelayError(@NonNull Function> mapper, boolean tillTheEnd, int prefetch) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); return RxJavaPlugins.onAssembly(new FlowableConcatMapMaybe<>(this, mapper, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY, prefetch)); @@ -7974,7 +8456,7 @@ public final Flowable concatMapMaybeDelayError(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure and honors @@ -7988,7 +8470,8 @@ public final Flowable concatMapMaybeDelayError(@NonNull Function Flowable concatMapMaybeDelayError(@NonNull Function Flowable concatMapSingle(@NonNull Function> mapper) { + public final <@NonNull R> Flowable concatMapSingle(@NonNull Function> mapper) { return concatMapSingle(mapper, 2); } @@ -8006,7 +8489,7 @@ public final Flowable concatMapSingle(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure and honors @@ -8024,7 +8507,9 @@ public final Flowable concatMapSingle(@NonNull Function Flowable concatMapSingle(@NonNull Function Flowable concatMapSingle(@NonNull Function> mapper, int prefetch) { + public final <@NonNull R> Flowable concatMapSingle(@NonNull Function> mapper, int prefetch) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); return RxJavaPlugins.onAssembly(new FlowableConcatMapSingle<>(this, mapper, ErrorMode.IMMEDIATE, prefetch)); @@ -8044,7 +8529,7 @@ public final Flowable concatMapSingle(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure and honors @@ -8058,7 +8543,8 @@ public final Flowable concatMapSingle(@NonNull Function Flowable concatMapSingle(@NonNull Function Flowable concatMapSingleDelayError(@NonNull Function> mapper) { + public final <@NonNull R> Flowable concatMapSingleDelayError(@NonNull Function> mapper) { return concatMapSingleDelayError(mapper, true, 2); } @@ -8076,7 +8562,7 @@ public final Flowable concatMapSingleDelayError(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure and honors @@ -8096,7 +8582,8 @@ public final Flowable concatMapSingleDelayError(@NonNull Function Flowable concatMapSingleDelayError(@NonNull Function Flowable concatMapSingleDelayError(@NonNull Function> mapper, boolean tillTheEnd) { + public final <@NonNull R> Flowable concatMapSingleDelayError(@NonNull Function> mapper, boolean tillTheEnd) { return concatMapSingleDelayError(mapper, tillTheEnd, 2); } @@ -8114,7 +8601,7 @@ public final Flowable concatMapSingleDelayError(@NonNull Function - * + * *
*
Backpressure:
*
The operator expects the upstream to support backpressure and honors @@ -8138,7 +8625,9 @@ public final Flowable concatMapSingleDelayError(@NonNull Function Flowable concatMapSingleDelayError(@NonNull Function Flowable concatMapSingleDelayError(@NonNull Function> mapper, boolean tillTheEnd, int prefetch) { + public final <@NonNull R> Flowable concatMapSingleDelayError(@NonNull Function> mapper, boolean tillTheEnd, int prefetch) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); return RxJavaPlugins.onAssembly(new FlowableConcatMapSingle<>(this, mapper, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY, prefetch)); } /** - * Returns a {@code Flowable} that emits the items emitted from the current {@link Publisher}, then the next, one after + * Returns a {@code Flowable} that emits the items emitted from the current {@code Flowable}, then the next, one after * the other, without interleaving them. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream. Both this and the {@code other} {@code Publisher}s + *
The operator honors backpressure from downstream. Both this and the {@code other} {@link Publisher}s * are expected to honor backpressure as well. If any of then violates this rule, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * {@link IllegalStateException} when the current {@code Flowable} completes.
*
Scheduler:
*
{@code concatWith} does not operate by default on a particular {@link Scheduler}.
*
* * @param other * a {@code Publisher} to be concatenated after the current - * @return a {@code Flowable} that emits items emitted by the two source {@code Publisher}s, one after the other, - * without interleaving them + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: Concat */ @CheckReturnValue @@ -8185,7 +8674,7 @@ public final Flowable concatWith(@NonNull Publisher other) { * Returns a {@code Flowable} that emits the items from this {@code Flowable} followed by the success item or error event * of the other {@link SingleSource}. *

- * + * *

*
Backpressure:
*
The operator supports backpressure and makes sure the success item of the other {@code SingleSource} @@ -8196,6 +8685,7 @@ public final Flowable concatWith(@NonNull Publisher other) { *

History: 2.1.10 - experimental * @param other the {@code SingleSource} whose signal should be emitted after this {@code Flowable} completes normally. * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -8211,7 +8701,7 @@ public final Flowable concatWith(@NonNull SingleSource other) { * Returns a {@code Flowable} that emits the items from this {@code Flowable} followed by the success item or terminal events * of the other {@link MaybeSource}. *

- * + * *

*
Backpressure:
*
The operator supports backpressure and makes sure the success item of the other {@code MaybeSource} @@ -8222,6 +8712,7 @@ public final Flowable concatWith(@NonNull SingleSource other) { *

History: 2.1.10 - experimental * @param other the {@code MaybeSource} whose signal should be emitted after this {@code Flowable} completes normally. * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -8237,7 +8728,7 @@ public final Flowable concatWith(@NonNull MaybeSource other) { * Returns a {@code Flowable} that emits items from this {@code Flowable} and when it completes normally, the * other {@link CompletableSource} is subscribed to and the returned {@code Flowable} emits its terminal events. *

- * + * *

*
Backpressure:
*
The operator does not interfere with backpressure between the current {@code Flowable} and the @@ -8250,6 +8741,7 @@ public final Flowable concatWith(@NonNull MaybeSource other) { *

History: 2.1.10 - experimental * @param other the {@code CompletableSource} to subscribe to once the current {@code Flowable} completes normally * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -8262,22 +8754,22 @@ public final Flowable concatWith(@NonNull CompletableSource other) { } /** - * Returns a {@link Single} that emits a {@link Boolean} that indicates whether the source {@link Publisher} emitted a + * Returns a {@link Single} that emits a {@link Boolean} that indicates whether the current {@code Flowable} emitted a * specified item. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure).
*
Scheduler:
*
{@code contains} does not operate by default on a particular {@link Scheduler}.
*
* * @param item - * the item to search for in the emissions from the source {@code Publisher} - * @return a {@code Single} that emits {@code true} if the specified item is emitted by the source {@code Publisher}, - * or {@code false} if the source {@code Publisher} completes without emitting that item + * the item to search for in the emissions from the current {@code Flowable} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code item} is {@code null} * @see ReactiveX operators documentation: Contains */ @CheckReturnValue @@ -8290,20 +8782,19 @@ public final Single contains(@NonNull Object item) { } /** - * Returns a {@link Single} that counts the total number of items emitted by the source {@link Publisher} and emits + * Returns a {@link Single} that counts the total number of items emitted by the current {@code Flowable} and emits * this count as a 64-bit {@link Long}. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure).
*
Scheduler:
*
{@code count} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code Single} that emits a single item: the number of items emitted by the source {@code Publisher} as a - * 64-bit {@code Long} item + * @return the new {@code Single} instance * @see ReactiveX operators documentation: Count */ @CheckReturnValue @@ -8315,13 +8806,13 @@ public final Single count() { } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher}, except that it drops items emitted by the - * source {@code Publisher} that are followed by another item within a computed debounce duration. + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, except that it drops items emitted by the + * current {@code Flowable} that are followed by another item within a computed debounce duration. *

- * + * *

* The delivery of the item happens on the thread of the first {@code onNext} or {@code onComplete} - * signal of the generated {@code Publisher} sequence, + * signal of the generated {@link Publisher} sequence, * which if takes too long, a newer item may arrive from the upstream, causing the * generated sequence to get cancelled, which may also interrupt any downstream blocking operation * (yielding an {@code InterruptedException}). It is recommended processing items @@ -8339,8 +8830,8 @@ public final Single count() { * the debounce value type (ignored) * @param debounceIndicator * function to retrieve a sequence that indicates the throttle duration for each item - * @return a {@code Flowable} that omits items emitted by the source {@code Publisher} that are followed by another item - * within a computed debounce duration + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code debounceIndicator} is {@code null} * @see ReactiveX operators documentation: Debounce * @see RxJava wiki: Backpressure */ @@ -8348,20 +8839,20 @@ public final Single count() { @NonNull @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable debounce(@NonNull Function> debounceIndicator) { + public final <@NonNull U> Flowable debounce(@NonNull Function> debounceIndicator) { Objects.requireNonNull(debounceIndicator, "debounceIndicator is null"); return RxJavaPlugins.onAssembly(new FlowableDebounce<>(this, debounceIndicator)); } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher}, except that it drops items emitted by the - * source {@code Publisher} that are followed by newer items before a timeout value expires. The timer resets on + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, except that it drops items emitted by the + * current {@code Flowable} that are followed by newer items before a timeout value expires. The timer resets on * each emission. *

- * Note: If items keep being emitted by the source {@code Publisher} faster than the timeout then no items - * will be emitted by the resulting {@code Publisher}. + * Note: If items keep being emitted by the current {@code Flowable} faster than the timeout then no items + * will be emitted by the resulting {@code Flowable}. *

- * + * *

* Delivery of the item after the grace period happens on the {@code computation} {@link Scheduler}'s * {@code Worker} which if takes too long, a newer item may arrive from the upstream, causing the @@ -8377,13 +8868,13 @@ public final Flowable debounce(@NonNull Function * * @param timeout - * the length of the window of time that must pass after the emission of an item from the source - * {@code Publisher} in which that {@code Publisher} emits no items in order for the item to be emitted by the - * resulting {@code Publisher} + * the length of the window of time that must pass after the emission of an item from the current + * {@code Flowable} in which it emits no items in order for the item to be emitted by the + * resulting {@code Flowable} * @param unit * the unit of time for the specified {@code timeout} - * @return a {@code Flowable} that filters out items from the source {@code Publisher} that are too quickly followed by - * newer items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Debounce * @see RxJava wiki: Backpressure * @see #throttleWithTimeout(long, TimeUnit) @@ -8397,14 +8888,14 @@ public final Flowable debounce(long timeout, @NonNull TimeUnit unit) { } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher}, except that it drops items emitted by the - * source {@code Publisher} that are followed by newer items before a timeout value expires on a specified + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, except that it drops items emitted by the + * current {@code Flowable} that are followed by newer items before a timeout value expires on a specified * {@link Scheduler}. The timer resets on each emission. *

- * Note: If items keep being emitted by the source {@code Publisher} faster than the timeout then no items - * will be emitted by the resulting {@code Publisher}. + * Note: If items keep being emitted by the current {@code Flowable} faster than the timeout then no items + * will be emitted by the resulting {@code Flowable}. *

- * + * *

* Delivery of the item after the grace period happens on the given {@code Scheduler}'s * {@code Worker} which if takes too long, a newer item may arrive from the upstream, causing the @@ -8420,15 +8911,15 @@ public final Flowable debounce(long timeout, @NonNull TimeUnit unit) { *

* * @param timeout - * the time each item has to be "the most recent" of those emitted by the source {@code Publisher} to + * the time each item has to be "the most recent" of those emitted by the current {@code Flowable} to * ensure that it's not dropped * @param unit * the unit of time for the specified {@code timeout} * @param scheduler * the {@code Scheduler} to use internally to manage the timers that handle the timeout for each * item - * @return a {@code Flowable} that filters out items from the source {@code Publisher} that are too quickly followed by - * newer items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Debounce * @see RxJava wiki: Backpressure * @see #throttleWithTimeout(long, TimeUnit, Scheduler) @@ -8440,18 +8931,70 @@ public final Flowable debounce(long timeout, @NonNull TimeUnit unit) { public final Flowable debounce(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new FlowableDebounceTimed<>(this, timeout, unit, scheduler)); + return RxJavaPlugins.onAssembly(new FlowableDebounceTimed<>(this, timeout, unit, scheduler, null)); + } + + /** + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, except that it drops items emitted by the + * current {@code Flowable} that are followed by newer items before a timeout value expires on a specified + * {@link Scheduler}. The timer resets on each emission. + *

+ * Note: If items keep being emitted by the current {@code Flowable} faster than the timeout then no items + * will be emitted by the resulting {@code Flowable}. + *

+ * + *

+ * Delivery of the item after the grace period happens on the given {@code Scheduler}'s + * {@code Worker} which if takes too long, a newer item may arrive from the upstream, causing the + * {@code Worker}'s task to get disposed, which may also interrupt any downstream blocking operation + * (yielding an {@code InterruptedException}). It is recommended processing items + * that may take long time to be moved to another thread via {@link #observeOn} applied after + * {@code debounce} itself. + *

+ *
Backpressure:
+ *
This operator does not support backpressure as it uses time to control data flow.
+ *
Scheduler:
+ *
You specify which {@code Scheduler} this operator will use.
+ *
+ * + * @param timeout + * the time each item has to be "the most recent" of those emitted by the current {@code Flowable} to + * ensure that it's not dropped + * @param unit + * the unit of time for the specified {@code timeout} + * @param scheduler + * the {@code Scheduler} to use internally to manage the timers that handle the timeout for each + * item + * @param onDropped + * called with the current entry when it has been replaced by a new one + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} or {@code onDropped} is {@code null} + * @see ReactiveX operators documentation: Debounce + * @see RxJava wiki: Backpressure + * @see #throttleWithTimeout(long, TimeUnit, Scheduler, Consumer) + * @since 3.1.6 - Experimental + */ + @CheckReturnValue + @NonNull + @BackpressureSupport(BackpressureKind.ERROR) + @SchedulerSupport(SchedulerSupport.CUSTOM) + @Experimental + public final Flowable debounce(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + Objects.requireNonNull(onDropped, "onDropped is null"); + return RxJavaPlugins.onAssembly(new FlowableDebounceTimed<>(this, timeout, unit, scheduler, onDropped)); } /** - * Returns a {@code Flowable} that emits the items emitted by the source {@link Publisher} or a specified default item - * if the source {@code Publisher} is empty. + * Returns a {@code Flowable} that emits the items emitted by the current {@code Flowable} or a specified default item + * if the current {@code Flowable} is empty. *

- * + * *

*
Backpressure:
- *
If the source {@code Publisher} is empty, this operator is guaranteed to honor backpressure from downstream. - * If the source {@code Publisher} is non-empty, it is expected to honor backpressure as well; if the rule is violated, + *
If the current {@code Flowable} is empty, this operator is guaranteed to honor backpressure from downstream. + * If the current {@code Flowable} is non-empty, it is expected to honor backpressure as well; if the rule is violated, * a {@link MissingBackpressureException} may get signaled somewhere downstream. *
*
Scheduler:
@@ -8459,9 +9002,9 @@ public final Flowable debounce(long timeout, @NonNull TimeUnit unit, @NonNull *
* * @param defaultItem - * the item to emit if the source {@code Publisher} emits no items - * @return a {@code Flowable} that emits either the specified default item if the source {@code Publisher} emits no - * items, or the items emitted by the source {@code Publisher} + * the item to emit if the current {@code Flowable} emits no items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX operators documentation: DefaultIfEmpty */ @CheckReturnValue @@ -8474,16 +9017,16 @@ public final Flowable defaultIfEmpty(@NonNull T defaultItem) { } /** - * Returns a {@code Flowable} that delays the emissions of the source {@link Publisher} via another {@code Publisher} on a + * Returns a {@code Flowable} that delays the emissions of the current {@code Flowable} via another {@link Publisher} on a * per-item basis. *

- * + * *

- * Note: the resulting {@code Publisher} will immediately propagate any {@code onError} notification - * from the source {@code Publisher}. + * Note: the resulting {@code Flowable} will immediately propagate any {@code onError} notification + * from the current {@code Flowable}. *

*
Backpressure:
- *
The operator doesn't interfere with the backpressure behavior which is determined by the source {@code Publisher}. + *
The operator doesn't interfere with the backpressure behavior which is determined by the current {@code Flowable}. * All of the other {@code Publisher}s supplied by the function are consumed * in an unbounded manner (i.e., no backpressure applied to them).
*
Scheduler:
@@ -8493,121 +9036,124 @@ public final Flowable defaultIfEmpty(@NonNull T defaultItem) { * @param * the item delay value type (ignored) * @param itemDelayIndicator - * a function that returns a {@code Publisher} for each item emitted by the source {@code Publisher}, which is - * then used to delay the emission of that item by the resulting {@code Publisher} until the {@code Publisher} + * a function that returns a {@code Publisher} for each item emitted by the current {@code Flowable}, which is + * then used to delay the emission of that item by the resulting {@code Flowable} until the {@code Publisher} * returned from {@code itemDelay} emits an item - * @return a {@code Flowable} that delays the emissions of the source {@code Publisher} via another {@code Publisher} on a - * per-item basis + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code itemDelayIndicator} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable delay(@NonNull Function> itemDelayIndicator) { + public final <@NonNull U> Flowable delay(@NonNull Function> itemDelayIndicator) { Objects.requireNonNull(itemDelayIndicator, "itemDelayIndicator is null"); return flatMap(FlowableInternalHelper.itemDelay(itemDelayIndicator)); } /** - * Returns a {@code Flowable} that emits the items emitted by the source {@link Publisher} shifted forward in time by a - * specified delay. The {@code onError} notification from the source {@code Publisher} is not delayed. + * Returns a {@code Flowable} that emits the items emitted by the current {@code Flowable} shifted forward in time by a + * specified delay. The {@code onError} notification from the current {@code Flowable} is not delayed. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with the backpressure behavior which is determined by the source {@code Publisher}.
+ *
The operator doesn't interfere with the backpressure behavior which is determined by the current {@code Flowable}.
*
Scheduler:
*
This version of {@code delay} operates by default on the {@code computation} {@link Scheduler}.
*
* - * @param delay + * @param time * the delay to shift the source by * @param unit * the {@link TimeUnit} in which {@code period} is defined - * @return the source {@code Publisher} shifted in time by the specified delay + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Flowable delay(long delay, @NonNull TimeUnit unit) { - return delay(delay, unit, Schedulers.computation(), false); + public final Flowable delay(long time, @NonNull TimeUnit unit) { + return delay(time, unit, Schedulers.computation(), false); } /** - * Returns a {@code Flowable} that emits the items emitted by the source {@link Publisher} shifted forward in time by a + * Returns a {@code Flowable} that emits the items emitted by the current {@code Flowable} shifted forward in time by a * specified delay. If {@code delayError} is {@code true}, error notifications will also be delayed. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with the backpressure behavior which is determined by the source {@code Publisher}.
+ *
The operator doesn't interfere with the backpressure behavior which is determined by the current {@code Flowable}.
*
Scheduler:
*
This version of {@code delay} operates by default on the {@code computation} {@link Scheduler}.
*
* - * @param delay + * @param time * the delay to shift the source by * @param unit * the {@link TimeUnit} in which {@code period} is defined * @param delayError * if {@code true}, the upstream exception is signaled with the given delay, after all preceding normal elements, * if {@code false}, the upstream exception is signaled immediately - * @return the source {@code Publisher} shifted in time by the specified delay + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Flowable delay(long delay, @NonNull TimeUnit unit, boolean delayError) { - return delay(delay, unit, Schedulers.computation(), delayError); + public final Flowable delay(long time, @NonNull TimeUnit unit, boolean delayError) { + return delay(time, unit, Schedulers.computation(), delayError); } /** - * Returns a {@code Flowable} that emits the items emitted by the source {@link Publisher} shifted forward in time by a - * specified delay. The {@code onError} notification from the source {@code Publisher} is not delayed. + * Returns a {@code Flowable} that emits the items emitted by the current {@code Flowable} shifted forward in time by a + * specified delay. The {@code onError} notification from the current {@code Flowable} is not delayed. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with the backpressure behavior which is determined by the source {@code Publisher}.
+ *
The operator doesn't interfere with the backpressure behavior which is determined by the current {@code Flowable}.
*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
* - * @param delay + * @param time * the delay to shift the source by * @param unit * the time unit of {@code delay} * @param scheduler * the {@code Scheduler} to use for delaying - * @return the source {@code Publisher} shifted in time by the specified delay + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Flowable delay(long delay, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return delay(delay, unit, scheduler, false); + public final Flowable delay(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + return delay(time, unit, scheduler, false); } /** - * Returns a {@code Flowable} that emits the items emitted by the source {@link Publisher} shifted forward in time by a + * Returns a {@code Flowable} that emits the items emitted by the current {@code Flowable} shifted forward in time by a * specified delay. If {@code delayError} is {@code true}, error notifications will also be delayed. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with the backpressure behavior which is determined by the source {@code Publisher}.
+ *
The operator doesn't interfere with the backpressure behavior which is determined by the current {@code Flowable}.
*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
* - * @param delay + * @param time * the delay to shift the source by * @param unit * the time unit of {@code delay} @@ -8616,31 +9162,32 @@ public final Flowable delay(long delay, @NonNull TimeUnit unit, @NonNull Sche * @param delayError * if {@code true}, the upstream exception is signaled with the given delay, after all preceding normal elements, * if {@code false}, the upstream exception is signaled immediately - * @return the source {@code Publisher} shifted in time by the specified delay + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Flowable delay(long delay, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError) { + public final Flowable delay(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new FlowableDelay<>(this, Math.max(0L, delay), unit, scheduler, delayError)); + return RxJavaPlugins.onAssembly(new FlowableDelay<>(this, Math.max(0L, time), unit, scheduler, delayError)); } /** - * Returns a {@code Flowable} that delays the subscription to and emissions from the source {@link Publisher} via another - * {@code Publisher} on a per-item basis. + * Returns a {@code Flowable} that delays the subscription to and emissions from the current {@code Flowable} via another + * {@link Publisher} on a per-item basis. *

- * + * *

- * Note: the resulting {@code Publisher} will immediately propagate any {@code onError} notification - * from the source {@code Publisher}. + * Note: the resulting {@code Flowable} will immediately propagate any {@code onError} notification + * from the current {@code Flowable}. *

*
Backpressure:
- *
The operator doesn't interfere with the backpressure behavior which is determined by the source {@code Publisher}. + *
The operator doesn't interfere with the backpressure behavior which is determined by the current {@code Flowable}. * All of the other {@code Publisher}s supplied by the functions are consumed * in an unbounded manner (i.e., no backpressure applied to them).
*
Scheduler:
@@ -8652,22 +9199,22 @@ public final Flowable delay(long delay, @NonNull TimeUnit unit, @NonNull Sche * @param * the item delay value type (ignored) * @param subscriptionIndicator - * a function that returns a {@code Publisher} that triggers the subscription to the source {@code Publisher} + * a function that returns a {@code Publisher} that triggers the subscription to the current {@code Flowable} * once it emits any item * @param itemDelayIndicator - * a function that returns a {@code Publisher} for each item emitted by the source {@code Publisher}, which is - * then used to delay the emission of that item by the resulting {@code Publisher} until the {@code Publisher} + * a function that returns a {@code Publisher} for each item emitted by the current {@code Flowable}, which is + * then used to delay the emission of that item by the resulting {@code Flowable} until the {@code Publisher} * returned from {@code itemDelay} emits an item - * @return a {@code Flowable} that delays the subscription and emissions of the source {@code Publisher} via another - * {@code Publisher} on a per-item basis + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code subscriptionIndicator} and {@code itemDelayIndicator} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable delay(@NonNull Publisher subscriptionIndicator, - @NonNull Function> itemDelayIndicator) { + public final <@NonNull U, @NonNull V> Flowable delay(@NonNull Publisher subscriptionIndicator, + @NonNull Function> itemDelayIndicator) { return delaySubscription(subscriptionIndicator).delay(itemDelayIndicator); } @@ -8685,73 +9232,74 @@ public final Flowable delay(@NonNull Publisher subscriptionIndicato * @param the value type of the other {@code Publisher}, irrelevant * @param subscriptionIndicator the other {@code Publisher} that should trigger the subscription * to this {@code Publisher}. - * @return a {@code Flowable} that delays the subscription to this {@code Publisher} - * until the other {@code Publisher} emits an element or completes normally. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code subscriptionIndicator} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable delaySubscription(@NonNull Publisher subscriptionIndicator) { + public final <@NonNull U> Flowable delaySubscription(@NonNull Publisher subscriptionIndicator) { Objects.requireNonNull(subscriptionIndicator, "subscriptionIndicator is null"); return RxJavaPlugins.onAssembly(new FlowableDelaySubscriptionOther<>(this, subscriptionIndicator)); } /** - * Returns a {@code Flowable} that delays the subscription to the source {@link Publisher} by a given amount of time. + * Returns a {@code Flowable} that delays the subscription to the current {@code Flowable} by a given amount of time. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with the backpressure behavior which is determined by the source {@code Publisher}.
+ *
The operator doesn't interfere with the backpressure behavior which is determined by the current {@code Flowable}.
*
Scheduler:
*
This version of {@code delaySubscription} operates by default on the {@code computation} {@link Scheduler}.
*
* - * @param delay + * @param time * the time to delay the subscription * @param unit * the time unit of {@code delay} - * @return a {@code Flowable} that delays the subscription to the source {@code Publisher} by the given amount + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Flowable delaySubscription(long delay, @NonNull TimeUnit unit) { - return delaySubscription(delay, unit, Schedulers.computation()); + public final Flowable delaySubscription(long time, @NonNull TimeUnit unit) { + return delaySubscription(time, unit, Schedulers.computation()); } /** - * Returns a {@code Flowable} that delays the subscription to the source {@link Publisher} by a given amount of time, + * Returns a {@code Flowable} that delays the subscription to the current {@code Flowable} by a given amount of time, * both waiting and subscribing on a given {@link Scheduler}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with the backpressure behavior which is determined by the source {@code Publisher}.
+ *
The operator doesn't interfere with the backpressure behavior which is determined by the current {@code Flowable}.
*
Scheduler:
*
You specify which {@code Scheduler} this operator will use.
*
* - * @param delay + * @param time * the time to delay the subscription * @param unit * the time unit of {@code delay} * @param scheduler * the {@code Scheduler} on which the waiting and subscription will happen - * @return a {@code Flowable} that delays the subscription to the source {@code Publisher} by a given - * amount, waiting and subscribing on the given {@code Scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Flowable delaySubscription(long delay, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return delaySubscription(timer(delay, unit, scheduler)); + public final Flowable delaySubscription(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + return delaySubscription(timer(time, unit, scheduler)); } /** @@ -8759,7 +9307,7 @@ public final Flowable delaySubscription(long delay, @NonNull TimeUnit unit, @ * {@link Notification} objects extracted from the source items via a selector function * into their respective {@link Subscriber} signal types. *

- * + * *

* The intended use of the {@code selector} function is to perform a * type-safe identity mapping (see example) on a source that is already of type @@ -8789,7 +9337,7 @@ public final Flowable delaySubscription(long delay, @NonNull TimeUnit unit, @ * with a {@link #never()} source. *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@link Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code dematerialize} does not operate by default on a particular {@link Scheduler}.
@@ -8799,8 +9347,8 @@ public final Flowable delaySubscription(long delay, @NonNull TimeUnit unit, @ * @param the output value type * @param selector function that returns the upstream item and should return a {@code Notification} to signal * the corresponding {@code Subscriber} event to the downstream. - * @return a {@code Flowable} that emits the items and notifications embedded in the {@code Notification} objects - * selected from the items emitted by the source {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code selector} is {@code null} * @see ReactiveX operators documentation: Dematerialize * @since 3.0.0 */ @@ -8808,16 +9356,16 @@ public final Flowable delaySubscription(long delay, @NonNull TimeUnit unit, @ @NonNull @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.PASS_THROUGH) - public final Flowable dematerialize(@NonNull Function<@NonNull ? super T, @NonNull Notification> selector) { + public final <@NonNull R> Flowable dematerialize(@NonNull Function<@NonNull ? super T, @NonNull Notification> selector) { Objects.requireNonNull(selector, "selector is null"); return RxJavaPlugins.onAssembly(new FlowableDematerialize<>(this, selector)); } /** - * Returns a {@code Flowable} that emits all items emitted by the source {@link Publisher} that are distinct + * Returns a {@code Flowable} that emits all items emitted by the current {@code Flowable} that are distinct * based on {@link Object#equals(Object)} comparison. *

- * + * *

* It is recommended the elements' class {@code T} in the flow overrides the default {@code Object.equals()} and {@link Object#hashCode()} to provide * a meaningful comparison between items as the default Java implementation only considers reference equivalence. @@ -8834,14 +9382,13 @@ public final Flowable dematerialize(@NonNull Function<@NonNull ? super T, * to the {@link #distinct(Function, Supplier)} overload. *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code distinct} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code Flowable} that emits only those items emitted by the source {@code Publisher} that are distinct from - * each other + * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: Distinct * @see #distinct(Function) * @see #distinct(Function, Supplier) @@ -8856,11 +9403,11 @@ public final Flowable distinct() { } /** - * Returns a {@code Flowable} that emits all items emitted by the source {@link Publisher} that are distinct according + * Returns a {@code Flowable} that emits all items emitted by the current {@code Flowable} that are distinct according * to a key selector function and based on {@link Object#equals(Object)} comparison of the objects * returned by the key selector function. *

- * + * *

* It is recommended the keys' class {@code K} overrides the default {@code Object.equals()} and {@link Object#hashCode()} to provide * a meaningful comparison between the key objects as the default Java implementation only considers reference equivalence. @@ -8877,7 +9424,7 @@ public final Flowable distinct() { * to the {@link #distinct(Function, Supplier)} overload. *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code distinct} does not operate by default on a particular {@link Scheduler}.
@@ -8887,7 +9434,8 @@ public final Flowable distinct() { * @param keySelector * a function that projects an emitted item to a key value that is used to decide whether an item * is distinct from another one or not - * @return a {@code Flowable} that emits those items emitted by the source {@code Publisher} that have distinct keys + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: Distinct * @see #distinct(Function, Supplier) */ @@ -8895,22 +9443,22 @@ public final Flowable distinct() { @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable distinct(@NonNull Function keySelector) { + public final <@NonNull K> Flowable distinct(@NonNull Function keySelector) { return distinct(keySelector, Functions.createHashSet()); } /** - * Returns a {@code Flowable} that emits all items emitted by the source {@link Publisher} that are distinct according + * Returns a {@code Flowable} that emits all items emitted by the current {@code Flowable} that are distinct according * to a key selector function and based on {@link Object#equals(Object)} comparison of the objects * returned by the key selector function. *

- * + * *

* It is recommended the keys' class {@code K} overrides the default {@code Object.equals()} and {@link Object#hashCode()} to provide * a meaningful comparison between the key objects as the default Java implementation only considers reference equivalence. *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code distinct} does not operate by default on a particular {@link Scheduler}.
@@ -8923,14 +9471,15 @@ public final Flowable distinct(@NonNull Function keySelecto * @param collectionSupplier * function called for each individual {@link Subscriber} to return a {@link Collection} subtype for holding the extracted * keys and whose add() method's return indicates uniqueness. - * @return a {@code Flowable} that emits those items emitted by the source {@code Publisher} that have distinct keys + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code keySelector} or {@code collectionSupplier} is {@code null} * @see ReactiveX operators documentation: Distinct */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable distinct(@NonNull Function keySelector, + public final <@NonNull K> Flowable distinct(@NonNull Function keySelector, @NonNull Supplier> collectionSupplier) { Objects.requireNonNull(keySelector, "keySelector is null"); Objects.requireNonNull(collectionSupplier, "collectionSupplier is null"); @@ -8938,10 +9487,10 @@ public final Flowable distinct(@NonNull Function keySelecto } /** - * Returns a {@code Flowable} that emits all items emitted by the source {@link Publisher} that are distinct from their + * Returns a {@code Flowable} that emits all items emitted by the current {@code Flowable} that are distinct from their * immediate predecessors based on {@link Object#equals(Object)} comparison. *

- * + * *

* It is recommended the elements' class {@code T} in the flow overrides the default {@code Object.equals()} to provide * a meaningful comparison between items as the default Java implementation only considers reference equivalence. @@ -8960,14 +9509,13 @@ public final Flowable distinct(@NonNull Function keySelecto * for example using {@code map(CharSequence::toString)} or {@code map(list -> Collections.unmodifiableList(new ArrayList<>(list)))}. *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code distinctUntilChanged} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code Flowable} that emits those items from the source {@code Publisher} that are distinct from their - * immediate predecessors + * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: Distinct * @see #distinctUntilChanged(BiPredicate) */ @@ -8980,11 +9528,11 @@ public final Flowable distinctUntilChanged() { } /** - * Returns a {@code Flowable} that emits all items emitted by the source {@link Publisher} that are distinct from their + * Returns a {@code Flowable} that emits all items emitted by the current {@code Flowable} that are distinct from their * immediate predecessors, according to a key selector function and based on {@link Object#equals(Object)} comparison * of those objects returned by the key selector function. *

- * + * *

* It is recommended the keys' class {@code K} overrides the default {@code Object.equals()} to provide * a meaningful comparison between the key objects as the default Java implementation only considers reference equivalence. @@ -9004,7 +9552,7 @@ public final Flowable distinctUntilChanged() { * for example using {@code map(CharSequence::toString)} or {@code map(list -> Collections.unmodifiableList(new ArrayList<>(list)))}. *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code distinctUntilChanged} does not operate by default on a particular {@link Scheduler}.
@@ -9014,24 +9562,24 @@ public final Flowable distinctUntilChanged() { * @param keySelector * a function that projects an emitted item to a key value that is used to decide whether an item * is distinct from another one or not - * @return a {@code Flowable} that emits those items from the source {@code Publisher} whose keys are distinct from - * those of their immediate predecessors + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: Distinct */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable distinctUntilChanged(@NonNull Function keySelector) { + public final <@NonNull K> Flowable distinctUntilChanged(@NonNull Function keySelector) { Objects.requireNonNull(keySelector, "keySelector is null"); return RxJavaPlugins.onAssembly(new FlowableDistinctUntilChanged<>(this, keySelector, ObjectHelper.equalsPredicate())); } /** - * Returns a {@code Flowable} that emits all items emitted by the source {@link Publisher} that are distinct from their + * Returns a {@code Flowable} that emits all items emitted by the current {@code Flowable} that are distinct from their * immediate predecessors when compared with each other via the provided comparator function. *

- * + * *

* Note that the operator always retains the latest item from upstream regardless of the comparison result * and uses it in the next comparison with the next upstream item. @@ -9044,7 +9592,7 @@ public final Flowable distinctUntilChanged(@NonNull Function Collections.unmodifiableList(new ArrayList<>(list)))}. *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code distinctUntilChanged} does not operate by default on a particular {@link Scheduler}.
@@ -9052,8 +9600,8 @@ public final Flowable distinctUntilChanged(@NonNull FunctionReactiveX operators documentation: Distinct * @since 2.0 */ @@ -9075,7 +9623,7 @@ public final Flowable distinctUntilChanged(@NonNull BiPredicate *
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@link Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code doFinally} does not operate by default on a particular {@link Scheduler}.
@@ -9085,6 +9633,7 @@ public final Flowable distinctUntilChanged(@NonNull BiPredicate *

History: 2.0.1 - experimental * @param onFinally the action called when this {@code Flowable} terminates or gets canceled + * @throws NullPointerException if {@code onFinally} is {@code null} * @return the new {@code Flowable} instance * @since 2.1 */ @@ -9103,7 +9652,7 @@ public final Flowable doFinally(@NonNull Action onFinally) { * should be thread-safe. *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@link Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code doAfterNext} does not operate by default on a particular {@link Scheduler}.
@@ -9113,6 +9662,7 @@ public final Flowable doFinally(@NonNull Action onFinally) { *
*

History: 2.0.1 - experimental * @param onAfterNext the {@link Consumer} that will be called after emitting an item from upstream to the downstream + * @throws NullPointerException if {@code onAfterNext} is {@code null} * @return the new {@code Flowable} instance * @since 2.1 */ @@ -9129,19 +9679,19 @@ public final Flowable doAfterNext(@NonNull Consumer onAfterNext) { * Registers an {@link Action} to be called when this {@link Publisher} invokes either * {@link Subscriber#onComplete onComplete} or {@link Subscriber#onError onError}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code doAfterTerminate} does not operate by default on a particular {@link Scheduler}.
*
* * @param onAfterTerminate - * an {@code Action} to be invoked when the source {@code Publisher} finishes - * @return a {@code Flowable} that emits the same items as the source {@code Publisher}, then invokes the - * {@code Action} + * an {@code Action} to be invoked when the current {@code Flowable} finishes + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onAfterTerminate} is {@code null} * @see ReactiveX operators documentation: Do * @see #doOnTerminate(Action) */ @@ -9157,7 +9707,7 @@ public final Flowable doAfterTerminate(@NonNull Action onAfterTerminate) { /** * Calls the cancel {@link Action} if the downstream cancels the sequence. *

- * + * *

* The action is shared between subscriptions and thus may be called concurrently from multiple * threads; the action must be thread-safe. @@ -9173,8 +9723,9 @@ public final Flowable doAfterTerminate(@NonNull Action onAfterTerminate) { *

* * @param onCancel - * the action that gets called when the source {@link Publisher}'s {@link Subscription} is canceled - * @return the source {@code Publisher} modified so as to call this {@code Action} when appropriate + * the action that gets called when the current {@code Flowable}'s {@link Subscription} is canceled + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onCancel} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -9186,20 +9737,21 @@ public final Flowable doOnCancel(@NonNull Action onCancel) { } /** - * Modifies the source {@link Publisher} so that it invokes an action when it calls {@code onComplete}. + * Invokes an {@link Action} just before the current {@code Flowable} calls {@code onComplete}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code doOnComplete} does not operate by default on a particular {@link Scheduler}.
*
* * @param onComplete - * the action to invoke when the source {@code Publisher} calls {@code onComplete} - * @return the source {@code Publisher} with the side-effecting behavior applied + * the action to invoke when the current {@code Flowable} calls {@code onComplete} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onComplete} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -9215,16 +9767,21 @@ public final Flowable doOnComplete(@NonNull Action onComplete) { * Calls the appropriate onXXX consumer (shared between all subscribers) whenever a signal with the same type * passes through, before forwarding them to downstream. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@link Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code doOnEach} does not operate by default on a particular {@link Scheduler}.
*
* - * @return the source {@code Publisher} with the side-effecting behavior applied + * @param onNext the {@link Consumer} to invoke when the current {@code Flowable} calls {@code onNext} + * @param onError the {@code Consumer} to invoke when the current {@code Flowable} calls {@code onError} + * @param onComplete the {@link Action} to invoke when the current {@code Flowable} calls {@code onComplete} + * @param onAfterTerminate the {@code Action} to invoke when the current {@code Flowable} calls {@code onAfterTerminate} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onNext}, {@code onError}, {@code onComplete} or {@code onAfterTerminate} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -9241,20 +9798,22 @@ private Flowable doOnEach(@NonNull Consumer onNext, @NonNull Consu } /** - * Modifies the source {@link Publisher} so that it invokes an action for each item it emits. + * Invokes a {@link Consumer} with a {@link Notification} instances matching the signals emitted by the current {@code Flowable} + * before they are forwarded to the downstream. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code doOnEach} does not operate by default on a particular {@link Scheduler}.
*
* * @param onNotification - * the action to invoke for each item emitted by the source {@code Publisher} - * @return the source {@code Publisher} with the side-effecting behavior applied + * the action to invoke for each item emitted by the current {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onNotification} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -9272,17 +9831,18 @@ public final Flowable doOnEach(@NonNull Consumer<@NonNull ? super Notificatio } /** - * Modifies the source {@link Publisher} so that it notifies a {@link Subscriber} for each item and terminal event it emits. + * Calls the appropriate methods of the given {@link Subscriber} when the current {@code Flowable} signals events before forwarding it + * to the downstream. *

* In case the {@code onError} of the supplied {@code Subscriber} throws, the downstream will receive a composite * exception containing the original exception and the exception thrown by {@code onError}. If either the * {@code onNext} or the {@code onComplete} method of the supplied {@code Subscriber} throws, the downstream will be * terminated and will receive this thrown exception. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code doOnEach} does not operate by default on a particular {@link Scheduler}.
@@ -9291,7 +9851,8 @@ public final Flowable doOnEach(@NonNull Consumer<@NonNull ? super Notificatio * @param subscriber * the {@code Subscriber} to be notified about {@code onNext}, {@code onError} and {@code onComplete} events on its * respective methods before the actual downstream {@code Subscriber} gets notified. - * @return the source {@code Publisher} with the side-effecting behavior applied + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code subscriber} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -9308,23 +9869,25 @@ public final Flowable doOnEach(@NonNull Subscriber subscriber) { } /** - * Modifies the source {@link Publisher} so that it invokes an action if it calls {@code onError}. + * Calls the given {@link Consumer} with the error {@link Throwable} if the current {@code Flowable} failed before forwarding it to + * the downstream. *

* In case the {@code onError} action throws, the downstream will receive a composite exception containing * the original exception and the exception thrown by {@code onError}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code doOnError} does not operate by default on a particular {@link Scheduler}.
*
* * @param onError - * the action to invoke if the source {@code Publisher} calls {@code onError} - * @return the source {@code Publisher} with the side-effecting behavior applied + * the action to invoke if the current {@code Flowable} calls {@code onError} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onError} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -9340,10 +9903,10 @@ public final Flowable doOnError(@NonNull Consumer onError) * Calls the appropriate {@code onXXX} method (shared between all {@link Subscriber}s) for the lifecycle events of * the sequence (subscription, cancellation, requesting). *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@link Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code doOnLifecycle} does not operate by default on a particular {@link Scheduler}.
@@ -9355,7 +9918,8 @@ public final Flowable doOnError(@NonNull Consumer onError) * a {@link LongConsumer} called with the request amount sent via {@link Subscription#request(long)} * @param onCancel * called when the downstream cancels the {@code Subscription} via {@link Subscription#cancel()} - * @return the source {@code Publisher} with the side-effecting behavior applied + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onSubscribe}, {@code onRequest} or {@code onCancel} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -9371,21 +9935,23 @@ public final Flowable doOnLifecycle(@NonNull Consumer o } /** - * Modifies the source {@link Publisher} so that it invokes an action when it calls {@code onNext}. + * Calls the given {@link Consumer} with the value emitted by the current {@code Flowable} before forwarding it to the downstream. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code doOnNext} does not operate by default on a particular {@link Scheduler}.
*
* * @param onNext - * the action to invoke when the source {@code Publisher} calls {@code onNext} - * @return the source {@code Publisher} with the side-effecting behavior applied + * the action to invoke when the current {@code Flowable} calls {@code onNext} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onNext} is {@code null} * @see ReactiveX operators documentation: Do + * @see #doAfterNext(Consumer) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.PASS_THROUGH) @@ -9397,23 +9963,24 @@ public final Flowable doOnNext(@NonNull Consumer onNext) { } /** - * Modifies the source {@link Publisher} so that it invokes the given action when it receives a - * request for more items. + * Calls the given {@link LongConsumer} with the request amount from the downstream before forwarding it + * to the current {@code Flowable}. *

* Note: This operator is for tracing the internal behavior of back-pressure request * patterns and generally intended for debugging use. *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code doOnRequest} does not operate by default on a particular {@link Scheduler}.
*
* * @param onRequest - * the action that gets called when a {@link Subscriber} requests items from this - * {@code Publisher} - * @return the source {@code Publisher} modified so as to call this {@link Action} when appropriate + * the action that gets called when a {@link Subscriber} requests items from the current + * {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onRequest} is {@code null} * @see ReactiveX operators * documentation: Do * @since 2.0 @@ -9427,23 +9994,23 @@ public final Flowable doOnRequest(@NonNull LongConsumer onRequest) { } /** - * Modifies the source {@link Publisher} so that it invokes the given action when it is subscribed from - * its subscribers. Each subscription will result in an invocation of the given action except when the - * source {@code Publisher} is reference counted, in which case the source {@code Publisher} will invoke - * the given action for the first subscription. + * Calls the given {@link Consumer} with the {@link Subscription} provided by the current {@code Flowable} upon + * subscription from the downstream before forwarding it to the subscriber's + * {@link Subscriber#onSubscribe(Subscription) onSubscribe} method. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code doOnSubscribe} does not operate by default on a particular {@link Scheduler}.
*
* * @param onSubscribe - * the {@link Consumer} that gets called when a {@link Subscriber} subscribes to the current {@code Flowable} - * @return the source {@code Publisher} modified so as to call this {@code Consumer} when appropriate + * the {@code Consumer} that gets called when a {@link Subscriber} subscribes to the current {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onSubscribe} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -9455,24 +10022,25 @@ public final Flowable doOnSubscribe(@NonNull Consumer o } /** - * Modifies the source {@link Publisher} so that it invokes an action when it calls {@code onComplete} or - * {@code onError}. + * Calls the given {@link Action} when the current {@code Flowable} completes normally or with an error before those signals + * are forwarded to the downstream. *

- * + * *

* This differs from {@code doAfterTerminate} in that this happens before the {@code onComplete} or * {@code onError} notification. *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s * backpressure behavior.
*
Scheduler:
*
{@code doOnTerminate} does not operate by default on a particular {@link Scheduler}.
*
* * @param onTerminate - * the action to invoke when the source {@code Publisher} calls {@code onComplete} or {@code onError} - * @return the source {@code Publisher} with the side-effecting behavior applied + * the action to invoke when the current {@code Flowable} calls {@code onComplete} or {@code onError} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onTerminate} is {@code null} * @see ReactiveX operators documentation: Do * @see #doAfterTerminate(Action) */ @@ -9489,18 +10057,18 @@ public final Flowable doOnTerminate(@NonNull Action onTerminate) { * Returns a {@link Maybe} that emits the single item at a specified index in a sequence of emissions from * this {@code Flowable} or completes if this {@code Flowable} sequence has fewer elements than index. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@link Publisher} in a bounded manner.
+ *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in a bounded manner.
*
Scheduler:
*
{@code elementAt} does not operate by default on a particular {@link Scheduler}.
*
* * @param index * the zero-based index of the item to retrieve - * @return a {@code Maybe} that emits a single item: the item at the specified position in the sequence of - * those emitted by the source {@code Publisher} + * @return the new {@code Maybe} instance + * @throws IndexOutOfBoundsException if {@code index} is negative * @see ReactiveX operators documentation: ElementAt */ @CheckReturnValue @@ -9518,10 +10086,10 @@ public final Maybe elementAt(long index) { * Returns a {@link Single} that emits the item found at a specified index in a sequence of emissions from * this {@code Flowable}, or a default item if that index is out of range. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@link Publisher} in a bounded manner.
+ *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in a bounded manner.
*
Scheduler:
*
{@code elementAt} does not operate by default on a particular {@link Scheduler}.
*
@@ -9530,10 +10098,10 @@ public final Maybe elementAt(long index) { * the zero-based index of the item to retrieve * @param defaultItem * the default item - * @return a {@code Single} that emits the item at the specified position in the sequence emitted by the source - * {@code Publisher}, or the default item if that index is outside the bounds of the source sequence + * @return the new {@code Single} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @throws IndexOutOfBoundsException - * if {@code index} is less than 0 + * if {@code index} is negative * @see ReactiveX operators documentation: ElementAt */ @CheckReturnValue @@ -9552,18 +10120,17 @@ public final Single elementAt(long index, @NonNull T defaultItem) { * Returns a {@link Single} that emits the item found at a specified index in a sequence of emissions from * this {@code Flowable} or signals a {@link NoSuchElementException} if this {@code Flowable} has fewer elements than index. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@link Publisher} in a bounded manner.
+ *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in a bounded manner.
*
Scheduler:
*
{@code elementAtOrError} does not operate by default on a particular {@link Scheduler}.
*
* * @param index * the zero-based index of the item to retrieve - * @return a {@code Single} that emits the item at the specified position in the sequence emitted by the source - * {@code Publisher}, or the default item if that index is outside the bounds of the source sequence + * @return the new {@code Single} instance * @throws IndexOutOfBoundsException * if {@code index} is less than 0 * @see ReactiveX operators documentation: ElementAt @@ -9580,22 +10147,22 @@ public final Single elementAtOrError(long index) { } /** - * Filters items emitted by a {@link Publisher} by only emitting those that satisfy a specified predicate. + * Filters items emitted by the current {@code Flowable} by only emitting those that satisfy a specified predicate. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code filter} does not operate by default on a particular {@link Scheduler}.
*
* * @param predicate - * a function that evaluates each item emitted by the source {@code Publisher}, returning {@code true} + * a function that evaluates each item emitted by the current {@code Flowable}, returning {@code true} * if it passes the filter - * @return a {@code Flowable} that emits only those items emitted by the source {@code Publisher} that the filter - * evaluates as {@code true} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @see ReactiveX operators documentation: Filter */ @CheckReturnValue @@ -9611,10 +10178,10 @@ public final Flowable filter(@NonNull Predicate predicate) { * Returns a {@link Maybe} that emits only the very first item emitted by this {@code Flowable} or * completes if this {@code Flowable} is empty. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@link Publisher} in a bounded manner.
+ *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in a bounded manner.
*
Scheduler:
*
{@code firstElement} does not operate by default on a particular {@link Scheduler}.
*
@@ -9634,18 +10201,18 @@ public final Maybe firstElement() { * Returns a {@link Single} that emits only the very first item emitted by this {@code Flowable}, or a default * item if this {@code Flowable} completes without emitting anything. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@link Publisher} in a bounded manner.
+ *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in a bounded manner.
*
Scheduler:
*
{@code first} does not operate by default on a particular {@link Scheduler}.
*
* * @param defaultItem - * the default item to emit if the source {@code Publisher} doesn't emit anything - * @return a {@code Single} that emits only the very first item from the source, or a default item if the - * source {@code Publisher} completes without emitting any items + * the default item to emit if the current {@code Flowable} doesn't emit anything + * @return the new {@code Single} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX operators documentation: First */ @CheckReturnValue @@ -9663,7 +10230,7 @@ public final Single first(@NonNull T defaultItem) { * *
*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@link Publisher} in a bounded manner.
+ *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in a bounded manner.
*
Scheduler:
*
{@code firstOrError} does not operate by default on a particular {@link Scheduler}.
*
@@ -9681,10 +10248,10 @@ public final Single firstOrError() { /** * Returns a {@code Flowable} that emits items based on applying a function that you supply to each item emitted - * by the source {@link Publisher}, where that function returns a {@code Publisher}, and then merging those resulting + * by the current {@code Flowable}, where that function returns a {@link Publisher}, and then merging those resulting * {@code Publisher}s and emitting the results of this merger. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The upstream {@code Flowable} is consumed @@ -9697,27 +10264,26 @@ public final Single firstOrError() { * * @param the value type of the inner {@code Publisher}s and the output type * @param mapper - * a function that, when applied to an item emitted by the source {@code Publisher}, returns a + * a function that, when applied to an item emitted by the current {@code Flowable}, returns a * {@code Publisher} - * @return a {@code Flowable} that emits the result of applying the transformation function to each item emitted - * by the source {@code Publisher} and merging the results of the {@code Publisher}s obtained from this - * transformation + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable flatMap(@NonNull Function> mapper) { + public final <@NonNull R> Flowable flatMap(@NonNull Function> mapper) { return flatMap(mapper, false, bufferSize(), bufferSize()); } /** * Returns a {@code Flowable} that emits items based on applying a function that you supply to each item emitted - * by the source {@link Publisher}, where that function returns a {@code Publisher}, and then merging those resulting + * by the current {@code Flowable}, where that function returns a {@link Publisher}, and then merging those resulting * {@code Publisher}s and emitting the results of this merger. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The upstream {@code Flowable} is consumed @@ -9730,31 +10296,30 @@ public final Flowable flatMap(@NonNull Function the value type of the inner {@code Publisher}s and the output type * @param mapper - * a function that, when applied to an item emitted by the source {@code Publisher}, returns a + * a function that, when applied to an item emitted by the current {@code Flowable}, returns a * {@code Publisher} * @param delayErrors * if {@code true}, exceptions from the current {@code Flowable} and all inner {@code Publisher}s are delayed until all of them terminate * if {@code false}, the first one signaling an exception will terminate the whole sequence immediately - * @return a {@code Flowable} that emits the result of applying the transformation function to each item emitted - * by the source {@code Publisher} and merging the results of the {@code Publisher}s obtained from this - * transformation + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable flatMap(@NonNull Function> mapper, boolean delayErrors) { + public final <@NonNull R> Flowable flatMap(@NonNull Function> mapper, boolean delayErrors) { return flatMap(mapper, delayErrors, bufferSize(), bufferSize()); } /** * Returns a {@code Flowable} that emits items based on applying a function that you supply to each item emitted - * by the source {@link Publisher}, where that function returns a {@code Publisher}, and then merging those resulting + * by the current {@code Flowable}, where that function returns a {@link Publisher}, and then merging those resulting * {@code Publisher}s and emitting the results of this merger, while limiting the maximum number of concurrent * subscriptions to these {@code Publisher}s. * - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. The upstream {@code Flowable} is consumed @@ -9767,13 +10332,13 @@ public final Flowable flatMap(@NonNull Function the value type of the inner {@code Publisher}s and the output type * @param mapper - * a function that, when applied to an item emitted by the source {@code Publisher}, returns a + * a function that, when applied to an item emitted by the current {@code Flowable}, returns a * {@code Publisher} * @param maxConcurrency * the maximum number of {@code Publisher}s that may be subscribed to concurrently - * @return a {@code Flowable} that emits the result of applying the transformation function to each item emitted - * by the source {@code Publisher} and merging the results of the {@code Publisher}s obtained from this - * transformation + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @@ -9781,17 +10346,17 @@ public final Flowable flatMap(@NonNull Function Flowable flatMap(@NonNull Function> mapper, int maxConcurrency) { + public final <@NonNull R> Flowable flatMap(@NonNull Function> mapper, int maxConcurrency) { return flatMap(mapper, false, maxConcurrency, bufferSize()); } /** * Returns a {@code Flowable} that emits items based on applying a function that you supply to each item emitted - * by the source {@link Publisher}, where that function returns a {@code Publisher}, and then merging those resulting + * by the current {@code Flowable}, where that function returns a {@link Publisher}, and then merging those resulting * {@code Publisher}s and emitting the results of this merger, while limiting the maximum number of concurrent * subscriptions to these {@code Publisher}s. * - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. The upstream {@code Flowable} is consumed @@ -9804,16 +10369,16 @@ public final Flowable flatMap(@NonNull Function the value type of the inner {@code Publisher}s and the output type * @param mapper - * a function that, when applied to an item emitted by the source {@code Publisher}, returns a + * a function that, when applied to an item emitted by the current {@code Flowable}, returns a * {@code Publisher} * @param maxConcurrency * the maximum number of {@code Publisher}s that may be subscribed to concurrently * @param delayErrors * if {@code true}, exceptions from the current {@code Flowable} and all inner {@code Publisher}s are delayed until all of them terminate * if {@code false}, the first one signaling an exception will terminate the whole sequence immediately - * @return a {@code Flowable} that emits the result of applying the transformation function to each item emitted - * by the source {@code Publisher} and merging the results of the {@code Publisher}s obtained from this - * transformation + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @@ -9821,17 +10386,17 @@ public final Flowable flatMap(@NonNull Function Flowable flatMap(@NonNull Function> mapper, boolean delayErrors, int maxConcurrency) { + public final <@NonNull R> Flowable flatMap(@NonNull Function> mapper, boolean delayErrors, int maxConcurrency) { return flatMap(mapper, delayErrors, maxConcurrency, bufferSize()); } /** * Returns a {@code Flowable} that emits items based on applying a function that you supply to each item emitted - * by the source {@link Publisher}, where that function returns a {@code Publisher}, and then merging those resulting + * by the current {@code Flowable}, where that function returns a {@link Publisher}, and then merging those resulting * {@code Publisher}s and emitting the results of this merger, while limiting the maximum number of concurrent * subscriptions to these {@code Publisher}s. * - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. The upstream {@code Flowable} is consumed @@ -9844,7 +10409,7 @@ public final Flowable flatMap(@NonNull Function the value type of the inner {@code Publisher}s and the output type * @param mapper - * a function that, when applied to an item emitted by the source {@code Publisher}, returns a + * a function that, when applied to an item emitted by the current {@code Flowable}, returns a * {@code Publisher} * @param maxConcurrency * the maximum number of {@code Publisher}s that may be subscribed to concurrently @@ -9853,9 +10418,9 @@ public final Flowable flatMap(@NonNull FunctionReactiveX operators documentation: FlatMap * @since 2.0 */ @@ -9863,7 +10428,7 @@ public final Flowable flatMap(@NonNull Function Flowable flatMap(@NonNull Function> mapper, + public final <@NonNull R> Flowable flatMap(@NonNull Function> mapper, boolean delayErrors, int maxConcurrency, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); @@ -9880,10 +10445,10 @@ public final Flowable flatMap(@NonNull Function - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. The upstream {@code Flowable} is consumed @@ -9897,24 +10462,24 @@ public final Flowable flatMap(@NonNull Function * the result type * @param onNextMapper - * a function that returns a {@code Publisher} to merge for each item emitted by the source {@code Publisher} + * a function that returns a {@code Publisher} to merge for each item emitted by the current {@code Flowable} * @param onErrorMapper - * a function that returns a {@code Publisher} to merge for an {@code onError} notification from the source - * {@code Publisher} + * a function that returns a {@code Publisher} to merge for an {@code onError} notification from the current + * {@code Flowable} * @param onCompleteSupplier - * a function that returns a {@code Publisher} to merge for an {@code onComplete} notification from the source - * {@code Publisher} - * @return a {@code Flowable} that emits the results of merging the {@code Publisher}s returned from applying the - * specified functions to the emissions and notifications of the source {@code Publisher} + * a function that returns a {@code Publisher} to merge for an {@code onComplete} notification from the current + * {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onNextMapper}, {@code onErrorMapper} or {@code onCompleteSupplier} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable flatMap( - @NonNull Function> onNextMapper, - @NonNull Function> onErrorMapper, + public final <@NonNull R> Flowable flatMap( + @NonNull Function> onNextMapper, + @NonNull Function> onErrorMapper, @NonNull Supplier> onCompleteSupplier) { Objects.requireNonNull(onNextMapper, "onNextMapper is null"); Objects.requireNonNull(onErrorMapper, "onErrorMapper is null"); @@ -9923,11 +10488,11 @@ public final Flowable flatMap( } /** - * Returns a {@code Flowable} that applies a function to each item emitted or notification raised by the source - * {@link Publisher} and then flattens the {@code Publisher}s returned from these functions and emits the resulting items, + * Returns a {@code Flowable} that applies a function to each item emitted or notification raised by the current + * {@code Flowable} and then flattens the {@link Publisher}s returned from these functions and emits the resulting items, * while limiting the maximum number of concurrent subscriptions to these {@code Publisher}s. * - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. The upstream {@code Flowable} is consumed @@ -9941,17 +10506,18 @@ public final Flowable flatMap( * @param * the result type * @param onNextMapper - * a function that returns a {@code Publisher} to merge for each item emitted by the source {@code Publisher} + * a function that returns a {@code Publisher} to merge for each item emitted by the current {@code Flowable} * @param onErrorMapper - * a function that returns a {@code Publisher} to merge for an {@code onError} notification from the source - * {@code Publisher} + * a function that returns a {@code Publisher} to merge for an {@code onError} notification from the current + * {@code Flowable} * @param onCompleteSupplier - * a function that returns a {@code Publisher} to merge for an {@code onComplete} notification from the source - * {@code Publisher} + * a function that returns a {@code Publisher} to merge for an {@code onComplete} notification from the current + * {@code Flowable} * @param maxConcurrency * the maximum number of {@code Publisher}s that may be subscribed to concurrently - * @return a {@code Flowable} that emits the results of merging the {@code Publisher}s returned from applying the - * specified functions to the emissions and notifications of the source {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onNextMapper}, {@code onErrorMapper} or {@code onCompleteSupplier} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @@ -9959,9 +10525,9 @@ public final Flowable flatMap( @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable flatMap( - @NonNull Function> onNextMapper, - @NonNull Function> onErrorMapper, + public final <@NonNull R> Flowable flatMap( + @NonNull Function> onNextMapper, + @NonNull Function> onErrorMapper, @NonNull Supplier> onCompleteSupplier, int maxConcurrency) { Objects.requireNonNull(onNextMapper, "onNextMapper is null"); @@ -9973,9 +10539,9 @@ public final Flowable flatMap( /** * Returns a {@code Flowable} that emits the results of a specified function to the pair of values emitted by the - * source {@link Publisher} and a specified collection {@code Publisher}. + * current {@code Flowable} and a specified collection {@link Publisher}. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The upstream {@code Flowable} is consumed @@ -9991,28 +10557,28 @@ public final Flowable flatMap( * @param * the type of items emitted by the combiner function * @param mapper - * a function that returns a {@code Publisher} for each item emitted by the source {@code Publisher} + * a function that returns a {@code Publisher} for each item emitted by the current {@code Flowable} * @param combiner * a function that combines one item emitted by each of the source and collection {@code Publisher}s and - * returns an item to be emitted by the resulting {@code Publisher} - * @return a {@code Flowable} that emits the results of applying a function to a pair of values emitted by the - * source {@code Publisher} and the collection {@code Publisher} + * returns an item to be emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable flatMap(@NonNull Function> mapper, + public final <@NonNull U, @NonNull R> Flowable flatMap(@NonNull Function> mapper, @NonNull BiFunction combiner) { return flatMap(mapper, combiner, false, bufferSize(), bufferSize()); } /** * Returns a {@code Flowable} that emits the results of a specified function to the pair of values emitted by the - * source {@link Publisher} and a specified collection {@code Publisher}. + * current {@code Flowable} and a specified inner {@link Publisher}. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The upstream {@code Flowable} is consumed @@ -10028,32 +10594,32 @@ public final Flowable flatMap(@NonNull Function * the type of items emitted by the combiner functions * @param mapper - * a function that returns a {@code Publisher} for each item emitted by the source {@code Publisher} + * a function that returns a {@code Publisher} for each item emitted by the current {@code Flowable} * @param combiner * a function that combines one item emitted by each of the source and collection {@code Publisher}s and - * returns an item to be emitted by the resulting {@code Publisher} + * returns an item to be emitted by the resulting {@code Flowable} * @param delayErrors * if {@code true}, exceptions from the current {@code Flowable} and all inner {@code Publisher}s are delayed until all of them terminate * if {@code false}, the first one signaling an exception will terminate the whole sequence immediately - * @return a {@code Flowable} that emits the results of applying a function to a pair of values emitted by the - * source {@code Publisher} and the collection {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable flatMap(@NonNull Function> mapper, + public final <@NonNull U, @NonNull R> Flowable flatMap(@NonNull Function> mapper, @NonNull BiFunction combiner, boolean delayErrors) { return flatMap(mapper, combiner, delayErrors, bufferSize(), bufferSize()); } /** * Returns a {@code Flowable} that emits the results of a specified function to the pair of values emitted by the - * source {@link Publisher} and a specified collection {@code Publisher}, while limiting the maximum number of concurrent + * current {@code Flowable} and a specified collection {@link Publisher}, while limiting the maximum number of concurrent * subscriptions to these {@code Publisher}s. * - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. The upstream {@code Flowable} is consumed @@ -10069,17 +10635,18 @@ public final Flowable flatMap(@NonNull Function * the type of items emitted by the combiner function * @param mapper - * a function that returns a {@code Publisher} for each item emitted by the source {@code Publisher} + * a function that returns a {@code Publisher} for each item emitted by the current {@code Flowable} * @param combiner * a function that combines one item emitted by each of the source and collection {@code Publisher}s and - * returns an item to be emitted by the resulting {@code Publisher} + * returns an item to be emitted by the resulting {@code Flowable} * @param maxConcurrency * the maximum number of {@code Publisher}s that may be subscribed to concurrently * @param delayErrors * if {@code true}, exceptions from the current {@code Flowable} and all inner {@code Publisher}s are delayed until all of them terminate * if {@code false}, the first one signaling an exception will terminate the whole sequence immediately - * @return a {@code Flowable} that emits the results of applying a function to a pair of values emitted by the - * source {@code Publisher} and the collection {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @@ -10087,17 +10654,17 @@ public final Flowable flatMap(@NonNull Function Flowable flatMap(@NonNull Function> mapper, + public final <@NonNull U, @NonNull R> Flowable flatMap(@NonNull Function> mapper, @NonNull BiFunction combiner, boolean delayErrors, int maxConcurrency) { return flatMap(mapper, combiner, delayErrors, maxConcurrency, bufferSize()); } /** * Returns a {@code Flowable} that emits the results of a specified function to the pair of values emitted by the - * source {@link Publisher} and a specified collection {@code Publisher}, while limiting the maximum number of concurrent + * current {@code Flowable} and a specified collection {@link Publisher}, while limiting the maximum number of concurrent * subscriptions to these {@code Publisher}s. * - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. The upstream {@code Flowable} is consumed @@ -10113,10 +10680,10 @@ public final Flowable flatMap(@NonNull Function * the type of items emitted by the combiner function * @param mapper - * a function that returns a {@code Publisher} for each item emitted by the source {@code Publisher} + * a function that returns a {@code Publisher} for each item emitted by the current {@code Flowable} * @param combiner * a function that combines one item emitted by each of the source and collection {@code Publisher}s and - * returns an item to be emitted by the resulting {@code Publisher} + * returns an item to be emitted by the resulting {@code Flowable} * @param maxConcurrency * the maximum number of {@code Publisher}s that may be subscribed to concurrently * @param delayErrors @@ -10124,8 +10691,9 @@ public final Flowable flatMap(@NonNull FunctionReactiveX operators documentation: FlatMap * @since 2.0 */ @@ -10133,7 +10701,7 @@ public final Flowable flatMap(@NonNull Function Flowable flatMap(@NonNull Function> mapper, + public final <@NonNull U, @NonNull R> Flowable flatMap(@NonNull Function> mapper, @NonNull BiFunction combiner, boolean delayErrors, int maxConcurrency, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); Objects.requireNonNull(combiner, "combiner is null"); @@ -10144,10 +10712,10 @@ public final Flowable flatMap(@NonNull Function --> - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. The upstream {@code Flowable} is consumed @@ -10163,14 +10731,15 @@ public final Flowable flatMap(@NonNull Function * the type of items emitted by the combiner function * @param mapper - * a function that returns a {@code Publisher} for each item emitted by the source {@code Publisher} + * a function that returns a {@code Publisher} for each item emitted by the current {@code Flowable} * @param combiner * a function that combines one item emitted by each of the source and collection {@code Publisher}s and - * returns an item to be emitted by the resulting {@code Publisher} + * returns an item to be emitted by the resulting {@code Flowable} * @param maxConcurrency * the maximum number of {@code Publisher}s that may be subscribed to concurrently - * @return a {@code Flowable} that emits the results of applying a function to a pair of values emitted by the - * source {@code Publisher} and the collection {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @@ -10178,7 +10747,7 @@ public final Flowable flatMap(@NonNull Function Flowable flatMap(@NonNull Function> mapper, + public final <@NonNull U, @NonNull R> Flowable flatMap(@NonNull Function> mapper, @NonNull BiFunction combiner, int maxConcurrency) { return flatMap(mapper, combiner, false, maxConcurrency, bufferSize()); } @@ -10194,6 +10763,7 @@ public final Flowable flatMap(@NonNull Function * @param mapper the function that received each source value and transforms them into {@code CompletableSource}s. * @return the new {@link Completable} instance + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @@ -10219,6 +10789,8 @@ public final Completable flatMapCompletable(@NonNull Function - * + * *
*
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s is - * expected to honor backpressure as well. If the source {@code Publisher} violates the rule, the operator will + *
The operator honors backpressure from downstream. The current {@code Flowable}s is + * expected to honor backpressure as well. If the current {@code Flowable} violates the rule, the operator will * signal a {@link MissingBackpressureException}.
*
Scheduler:
*
{@code flatMapIterable} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of item emitted by the resulting {@code Iterable} + * the output type and the element type of the {@code Iterable}s * @param mapper * a function that returns an {@code Iterable} sequence of values for when given an item emitted by the - * source {@code Publisher} - * @return a {@code Flowable} that emits the results of merging the items emitted by the source {@code Publisher} with - * the values in the {@code Iterable}s corresponding to those items, as generated by {@code collectionSelector} + * current {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable flatMapIterable(@NonNull Function> mapper) { + public final <@NonNull U> Flowable flatMapIterable(@NonNull Function> mapper) { return flatMapIterable(mapper, bufferSize()); } /** - * Returns a {@code Flowable} that merges each item emitted by the source {@link Publisher} with the values in an - * {@link Iterable} corresponding to that item that is generated by a selector. + * Merges {@link Iterable}s generated by a mapper {@link Function} for each individual item emitted by + * the current {@code Flowable} into a single {@code Flowable} sequence. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s is - * expected to honor backpressure as well. If the source {@code Publisher} violates the rule, the operator will + *
The operator honors backpressure from downstream. The current {@code Flowable}s is + * expected to honor backpressure as well. If the current {@code Flowable} violates the rule, the operator will * signal a {@link MissingBackpressureException}.
*
Scheduler:
*
{@code flatMapIterable} does not operate by default on a particular {@link Scheduler}.
@@ -10279,71 +10851,75 @@ public final Flowable flatMapIterable(@NonNull FunctionReactiveX operators documentation: FlatMap */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable flatMapIterable(@NonNull Function> mapper, int bufferSize) { + public final <@NonNull U> Flowable flatMapIterable(@NonNull Function> mapper, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); return RxJavaPlugins.onAssembly(new FlowableFlattenIterable<>(this, mapper, bufferSize)); } /** - * Returns a {@code Flowable} that emits the results of applying a function to the pair of values from the source - * {@link Publisher} and an {@link Iterable} corresponding to that item that is generated by a selector. + * Merges {@link Iterable}s generated by a mapper {@link Function} for each individual item emitted by + * the current {@code Flowable} into a single {@code Flowable} sequence where the resulting items will + * be the combination of the original item and each inner item of the respective {@code Iterable} as returned + * by the {@code resultSelector} {@link BiFunction}. *

* *

*
Backpressure:
- *
The operator honors backpressure from downstream and the source {@code Publisher}s is - * consumed in an unbounded manner (i.e., no backpressure is applied to it).
+ *
The operator honors backpressure from downstream and the current {@code Flowable}s is + * consumed in a bounded manner (requesting {@link #bufferSize()} items upfront, then 75% of it after 75% received).
*
Scheduler:
*
{@code flatMapIterable} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the collection element type + * the element type of the {@code Iterable}s * @param - * the type of item emitted by the resulting {@code Iterable} + * the output type as determined by the {@code resultSelector} function * @param mapper - * a function that returns an {@code Iterable} sequence of values for each item emitted by the source - * {@code Publisher} - * @param resultSelector - * a function that returns an item based on the item emitted by the source {@code Publisher} and the + * a function that returns an {@code Iterable} sequence of values for each item emitted by the current + * {@code Flowable} + * @param combiner + * a function that returns an item based on the item emitted by the current {@code Flowable} and the * {@code Iterable} returned for that item by the {@code collectionSelector} - * @return a {@code Flowable} that emits the items returned by {@code resultSelector} for each item in the source - * {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable flatMapIterable(@NonNull Function> mapper, - @NonNull BiFunction resultSelector) { + public final <@NonNull U, @NonNull V> Flowable flatMapIterable(@NonNull Function> mapper, + @NonNull BiFunction combiner) { Objects.requireNonNull(mapper, "mapper is null"); - Objects.requireNonNull(resultSelector, "resultSelector is null"); - return flatMap(FlowableInternalHelper.flatMapIntoIterable(mapper), resultSelector, false, bufferSize(), bufferSize()); + Objects.requireNonNull(combiner, "combiner is null"); + return flatMap(FlowableInternalHelper.flatMapIntoIterable(mapper), combiner, false, bufferSize(), bufferSize()); } /** - * Returns a {@code Flowable} that merges each item emitted by the source {@link Publisher} with the values in an - * {@link Iterable} corresponding to that item that is generated by a selector, while limiting the number of concurrent - * subscriptions to these {@code Publisher}s. + * Merges {@link Iterable}s generated by a mapper {@link Function} for each individual item emitted by + * the current {@code Flowable} into a single {@code Flowable} sequence where the resulting items will + * be the combination of the original item and each inner item of the respective {@code Iterable} as returned + * by the {@code resultSelector} {@link BiFunction}. *

* *

*
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s is - * expected to honor backpressure as well. If the source {@code Publisher} violates the rule, the operator will + *
The operator honors backpressure from downstream. The current {@code Flowable}s is + * expected to honor backpressure as well. If the current {@code Flowable} violates the rule, the operator will * signal a {@link MissingBackpressureException}.
*
Scheduler:
*
{@code flatMapIterable} does not operate by default on a particular {@link Scheduler}.
@@ -10352,17 +10928,18 @@ public final Flowable flatMapIterable(@NonNull Function * the element type of the inner {@code Iterable} sequences * @param - * the type of item emitted by the resulting {@code Publisher} + * the type of item emitted by the resulting {@code Flowable} * @param mapper * a function that returns an {@code Iterable} sequence of values for when given an item emitted by the - * source {@code Publisher} - * @param resultSelector - * a function that returns an item based on the item emitted by the source {@code Publisher} and the + * current {@code Flowable} + * @param combiner + * a function that returns an item based on the item emitted by the current {@code Flowable} and the * {@code Iterable} returned for that item by the {@code collectionSelector} * @param prefetch * the number of elements to prefetch from the current {@code Flowable} - * @return a {@code Flowable} that emits the results of merging the items emitted by the source {@code Publisher} with - * the values in the {@code Iterable}s corresponding to those items, as generated by {@code collectionSelector} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @@ -10370,16 +10947,18 @@ public final Flowable flatMapIterable(@NonNull Function Flowable flatMapIterable(@NonNull Function> mapper, - @NonNull BiFunction resultSelector, int prefetch) { + public final <@NonNull U, @NonNull V> Flowable flatMapIterable(@NonNull Function> mapper, + @NonNull BiFunction combiner, int prefetch) { Objects.requireNonNull(mapper, "mapper is null"); - Objects.requireNonNull(resultSelector, "resultSelector is null"); - return flatMap(FlowableInternalHelper.flatMapIntoIterable(mapper), resultSelector, false, bufferSize(), prefetch); + Objects.requireNonNull(combiner, "combiner is null"); + return flatMap(FlowableInternalHelper.flatMapIntoIterable(mapper), combiner, false, bufferSize(), prefetch); } /** * Maps each element of the upstream {@code Flowable} into {@link MaybeSource}s, subscribes to all of them * and merges their {@code onSuccess} values, in no particular order, into a single {@code Flowable} sequence. + *

+ * *

*
Backpressure:
*
The operator consumes the upstream in an unbounded manner.
@@ -10389,12 +10968,13 @@ public final Flowable flatMapIterable(@NonNull Function the result value type * @param mapper the function that received each source value and transforms them into {@code MaybeSource}s. * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable flatMapMaybe(@NonNull Function> mapper) { + public final <@NonNull R> Flowable flatMapMaybe(@NonNull Function> mapper) { return flatMapMaybe(mapper, false, Integer.MAX_VALUE); } @@ -10402,6 +10982,8 @@ public final Flowable flatMapMaybe(@NonNull Function + * *
*
Backpressure:
*
If {@code maxConcurrency == }{@link Integer#MAX_VALUE} the operator consumes the upstream in an unbounded manner. @@ -10416,12 +10998,14 @@ public final Flowable flatMapMaybe(@NonNull Function Flowable flatMapMaybe(@NonNull Function> mapper, boolean delayErrors, int maxConcurrency) { + public final <@NonNull R> Flowable flatMapMaybe(@NonNull Function> mapper, boolean delayErrors, int maxConcurrency) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); return RxJavaPlugins.onAssembly(new FlowableFlatMapMaybe<>(this, mapper, delayErrors, maxConcurrency)); @@ -10439,12 +11023,13 @@ public final Flowable flatMapMaybe(@NonNull Function the result value type * @param mapper the function that received each source value and transforms them into {@code SingleSource}s. * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable flatMapSingle(@NonNull Function> mapper) { + public final <@NonNull R> Flowable flatMapSingle(@NonNull Function> mapper) { return flatMapSingle(mapper, false, Integer.MAX_VALUE); } @@ -10466,24 +11051,26 @@ public final Flowable flatMapSingle(@NonNull Function Flowable flatMapSingle(@NonNull Function> mapper, boolean delayErrors, int maxConcurrency) { + public final <@NonNull R> Flowable flatMapSingle(@NonNull Function> mapper, boolean delayErrors, int maxConcurrency) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); return RxJavaPlugins.onAssembly(new FlowableFlatMapSingle<>(this, mapper, delayErrors, maxConcurrency)); } /** - * Subscribes to the {@link Publisher} and receives notifications for each element. + * Subscribes to the current {@code Flowable} and receives notifications for each element. *

* Alias to {@link #subscribe(Consumer)} *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner (i.e., no + *
The operator consumes the current {@code Flowable} in an unbounded manner (i.e., no * backpressure is applied to it).
*
Scheduler:
*
{@code forEach} does not operate by default on a particular {@link Scheduler}.
@@ -10506,7 +11093,7 @@ public final Disposable forEach(@NonNull Consumer onNext) { } /** - * Subscribes to the {@link Publisher} and receives notifications for each element until the + * Subscribes to the current {@code Flowable} and receives notifications for each element until the * {@code onNext} Predicate returns {@code false}. *

* If the {@code Flowable} emits an error, it is wrapped into an @@ -10514,7 +11101,7 @@ public final Disposable forEach(@NonNull Consumer onNext) { * and routed to the {@link RxJavaPlugins#onError(Throwable)} handler. *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner (i.e., no + *
The operator consumes the current {@code Flowable} in an unbounded manner (i.e., no * backpressure is applied to it).
*
Scheduler:
*
{@code forEachWhile} does not operate by default on a particular {@link Scheduler}.
@@ -10537,11 +11124,11 @@ public final Disposable forEachWhile(@NonNull Predicate onNext) { } /** - * Subscribes to the {@link Publisher} and receives notifications for each element and error events until the + * Subscribes to the current {@code Flowable} and receives notifications for each element and error events until the * {@code onNext} Predicate returns {@code false}. *
*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner (i.e., no + *
The operator consumes the current {@code Flowable} in an unbounded manner (i.e., no * backpressure is applied to it).
*
Scheduler:
*
{@code forEachWhile} does not operate by default on a particular {@link Scheduler}.
@@ -10554,8 +11141,7 @@ public final Disposable forEachWhile(@NonNull Predicate onNext) { * @return * a {@link Disposable} that allows canceling an asynchronous sequence * @throws NullPointerException - * if {@code onNext} is {@code null}, or - * if {@code onError} is {@code null} + * if {@code onNext} or {@code onError} is {@code null} * @see ReactiveX operators documentation: Subscribe */ @CheckReturnValue @@ -10567,11 +11153,11 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN } /** - * Subscribes to the {@link Publisher} and receives notifications for each element and the terminal events until the + * Subscribes to the current {@code Flowable} and receives notifications for each element and the terminal events until the * {@code onNext} Predicate returns {@code false}. *
*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner (i.e., no + *
The operator consumes the current {@code Flowable} in an unbounded manner (i.e., no * backpressure is applied to it).
*
Scheduler:
*
{@code forEachWhile} does not operate by default on a particular {@link Scheduler}.
@@ -10586,9 +11172,7 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN * @return * a {@link Disposable} that allows canceling an asynchronous sequence * @throws NullPointerException - * if {@code onNext} is {@code null}, or - * if {@code onError} is {@code null}, or - * if {@code onComplete} is {@code null} + * if {@code onNext}, {@code onError} or {@code onComplete} is {@code null} * @see ReactiveX operators documentation: Subscribe */ @CheckReturnValue @@ -10607,13 +11191,13 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN } /** - * Groups the items emitted by a {@link Publisher} according to a specified criterion, and emits these + * Groups the items emitted by the current {@code Flowable} according to a specified criterion, and emits these * grouped items as {@link GroupedFlowable}s. The emitted {@code GroupedFlowable} allows only a single * {@link Subscriber} during its lifetime and if this {@code Subscriber} cancels before the * source terminates, the next emission by the source having the same key will trigger a new * {@code GroupedFlowable} emission. *

- * + * *

* Note: A {@code GroupedFlowable} will cache the items it is to emit until such time as it * is subscribed to. For this reason, in order to avoid memory leaks, you should not simply ignore those @@ -10650,9 +11234,8 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN * a function that extracts the key for each item * @param * the key type - * @return a {@code Publisher} that emits {@code GroupedFlowable}s, each of which corresponds to a - * unique key value and each of which emits those items from the source {@code Publisher} that share that - * key value + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: GroupBy * @see #groupBy(Function, boolean) * @see #groupBy(Function, Function) @@ -10661,18 +11244,18 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable> groupBy(@NonNull Function keySelector) { + public final <@NonNull K> Flowable> groupBy(@NonNull Function keySelector) { return groupBy(keySelector, Functions.identity(), false, bufferSize()); } /** - * Groups the items emitted by a {@link Publisher} according to a specified criterion, and emits these + * Groups the items emitted by the current {@code Flowable} according to a specified criterion, and emits these * grouped items as {@link GroupedFlowable}s. The emitted {@code GroupedFlowable} allows only a single * {@link Subscriber} during its lifetime and if this {@code Subscriber} cancels before the * source terminates, the next emission by the source having the same key will trigger a new * {@code GroupedFlowable} emission. *

- * + * *

* Note: A {@code GroupedFlowable} will cache the items it is to emit until such time as it * is subscribed to. For this reason, in order to avoid memory leaks, you should not simply ignore those @@ -10712,27 +11295,26 @@ public final Flowable> groupBy(@NonNull FunctionReactiveX operators documentation: GroupBy */ @CheckReturnValue @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable> groupBy(@NonNull Function keySelector, boolean delayError) { + public final <@NonNull K> Flowable> groupBy(@NonNull Function keySelector, boolean delayError) { return groupBy(keySelector, Functions.identity(), delayError, bufferSize()); } /** - * Groups the items emitted by a {@link Publisher} according to a specified criterion, and emits these + * Groups the items emitted by the current {@code Flowable} according to a specified criterion, and emits these * grouped items as {@link GroupedFlowable}s. The emitted {@code GroupedFlowable} allows only a single * {@link Subscriber} during its lifetime and if this {@code Subscriber} cancels before the * source terminates, the next emission by the source having the same key will trigger a new * {@code GroupedFlowable} emission. *

- * + * *

* Note: A {@code GroupedFlowable} will cache the items it is to emit until such time as it * is subscribed to. For this reason, in order to avoid memory leaks, you should not simply ignore those @@ -10773,9 +11355,8 @@ public final Flowable> groupBy(@NonNull Function * the element type - * @return a {@code Publisher} that emits {@code GroupedFlowable}s, each of which corresponds to a - * unique key value and each of which emits those items from the source {@code Publisher} that share that - * key value + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code keySelector} or {@code valueSelector} is {@code null} * @see ReactiveX operators documentation: GroupBy * @see #groupBy(Function, Function, boolean) * @see #groupBy(Function, Function, boolean, int) @@ -10785,19 +11366,19 @@ public final Flowable> groupBy(@NonNull Function Flowable> groupBy(@NonNull Function keySelector, + public final <@NonNull K, @NonNull V> Flowable> groupBy(@NonNull Function keySelector, @NonNull Function valueSelector) { return groupBy(keySelector, valueSelector, false, bufferSize()); } /** - * Groups the items emitted by a {@link Publisher} according to a specified criterion, and emits these + * Groups the items emitted by the current {@code Flowable} according to a specified criterion, and emits these * grouped items as {@link GroupedFlowable}s. The emitted {@code GroupedFlowable} allows only a single * {@link Subscriber} during its lifetime and if this {@code Subscriber} cancels before the * source terminates, the next emission by the source having the same key will trigger a new * {@code GroupedFlowable} emission. *

- * + * *

* Note: A {@code GroupedFlowable} will cache the items it is to emit until such time as it * is subscribed to. For this reason, in order to avoid memory leaks, you should not simply ignore those @@ -10841,9 +11422,8 @@ public final Flowable> groupBy(@NonNull FunctionReactiveX operators documentation: GroupBy * @see #groupBy(Function, Function, boolean, int) */ @@ -10851,19 +11431,19 @@ public final Flowable> groupBy(@NonNull Function Flowable> groupBy(@NonNull Function keySelector, + public final <@NonNull K, @NonNull V> Flowable> groupBy(@NonNull Function keySelector, @NonNull Function valueSelector, boolean delayError) { return groupBy(keySelector, valueSelector, delayError, bufferSize()); } /** - * Groups the items emitted by a {@link Publisher} according to a specified criterion, and emits these + * Groups the items emitted by the current {@code Flowable} according to a specified criterion, and emits these * grouped items as {@link GroupedFlowable}s. The emitted {@code GroupedFlowable} allows only a single * {@link Subscriber} during its lifetime and if this {@code Subscriber} cancels before the * source terminates, the next emission by the source having the same key will trigger a new * {@code GroupedFlowable} emission. *

- * + * *

* Note: A {@code GroupedFlowable} will cache the items it is to emit until such time as it * is subscribed to. For this reason, in order to avoid memory leaks, you should not simply ignore those @@ -10909,16 +11489,16 @@ public final Flowable> groupBy(@NonNull Function * the element type - * @return a {@code Publisher} that emits {@code GroupedFlowable}s, each of which corresponds to a - * unique key value and each of which emits those items from the source {@code Publisher} that share that - * key value + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code keySelector} or {@code valueSelector} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: GroupBy */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.SPECIAL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable> groupBy(@NonNull Function keySelector, + public final <@NonNull K, @NonNull V> Flowable> groupBy(@NonNull Function keySelector, @NonNull Function valueSelector, boolean delayError, int bufferSize) { Objects.requireNonNull(keySelector, "keySelector is null"); @@ -10929,7 +11509,7 @@ public final Flowable> groupBy(@NonNull Function Flowable> groupBy(@NonNull Function

* *

- * + * *

* Note: A {@code GroupedFlowable} will cache the items it is to emit until such time as it * is subscribed to. For this reason, in order to avoid memory leaks, you should not simply ignore those @@ -11028,9 +11608,9 @@ public final Flowable> groupBy(@NonNull Function * the element type - * @return a {@code Publisher} that emits {@code GroupedFlowable}s, each of which corresponds to a - * unique key value and each of which emits those items from the source {@code Publisher} that share that - * key value + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code keySelector}, {@code valueSelector} or {@code evictingMapFactory} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: GroupBy * * @since 2.2 @@ -11039,7 +11619,7 @@ public final Flowable> groupBy(@NonNull Function Flowable> groupBy(@NonNull Function keySelector, + public final <@NonNull K, @NonNull V> Flowable> groupBy(@NonNull Function keySelector, @NonNull Function valueSelector, boolean delayError, int bufferSize, @NonNull Function, ? extends Map> evictingMapFactory) { @@ -11057,7 +11637,7 @@ public final Flowable> groupBy(@NonNull Function - * + * *

*
Backpressure:
*
The operator doesn't support backpressure and consumes all participating {@code Publisher}s in @@ -11071,28 +11651,28 @@ public final Flowable> groupBy(@NonNull Function the element type of the right duration {@code Publisher}s * @param the result type * @param other - * the other {@code Publisher} to correlate items from the source {@code Publisher} with + * the other {@code Publisher} to correlate items from the current {@code Flowable} with * @param leftEnd * a function that returns a {@code Publisher} whose emissions indicate the duration of the values of - * the source {@code Publisher} + * the current {@code Flowable} * @param rightEnd * a function that returns a {@code Publisher} whose emissions indicate the duration of the values of * the {@code right} {@code Publisher} * @param resultSelector * a function that takes an item emitted by each {@code Publisher} and returns the value to be emitted - * by the resulting {@code Publisher} - * @return a {@code Flowable} that emits items based on combining those items emitted by the source {@code Publisher}s - * whose durations overlap + * by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other}, {@code leftEnd}, {@code rightEnd} or {@code resultSelector} is {@code null} * @see ReactiveX operators documentation: Join */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable groupJoin( + public final <@NonNull TRight, @NonNull TLeftEnd, @NonNull TRightEnd, @NonNull R> Flowable groupJoin( @NonNull Publisher other, - @NonNull Function> leftEnd, - @NonNull Function> rightEnd, + @NonNull Function> leftEnd, + @NonNull Function> rightEnd, @NonNull BiFunction, ? extends R> resultSelector) { Objects.requireNonNull(other, "other is null"); Objects.requireNonNull(leftEnd, "leftEnd is null"); @@ -11127,19 +11707,18 @@ public final Flowable hide() { } /** - * Ignores all items emitted by the source {@link Publisher} and only calls {@code onComplete} or {@code onError}. + * Ignores all items emitted by the current {@code Flowable} and only calls {@code onComplete} or {@code onError}. *

- * + * *

*
Backpressure:
- *
This operator ignores backpressure as it doesn't emit any elements and consumes the source {@code Publisher} + *
This operator ignores backpressure as it doesn't emit any elements and consumes the current {@code Flowable} * in an unbounded manner (i.e., no backpressure is applied to it).
*
Scheduler:
*
{@code ignoreElements} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@link Completable} that only calls {@code onComplete} or {@code onError}, based on which one is - * called by the source {@code Publisher} + * @return the new {@link Completable} instance * @see ReactiveX operators documentation: IgnoreElements */ @CheckReturnValue @@ -11151,21 +11730,21 @@ public final Completable ignoreElements() { } /** - * Returns a {@link Single} that emits {@code true} if the source {@link Publisher} is empty, otherwise {@code false}. + * Returns a {@link Single} that emits {@code true} if the current {@code Flowable} is empty, otherwise {@code false}. *

* In Rx.Net this is negated as the {@code any} {@link Subscriber} but we renamed this in RxJava to better match Java * naming idioms. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure).
*
Scheduler:
*
{@code isEmpty} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code Single} that emits a {@link Boolean} + * @return the new {@code Single} instance * @see ReactiveX operators documentation: Contains */ @CheckReturnValue @@ -11182,7 +11761,7 @@ public final Single isEmpty() { * There are no guarantees in what order the items get combined when multiple * items from one or both source {@code Publisher}s overlap. *

- * + * *

*
Backpressure:
*
The operator doesn't support backpressure and consumes all participating {@code Publisher}s in @@ -11198,26 +11777,26 @@ public final Single isEmpty() { * @param other * the second {@code Publisher} to join items from * @param leftEnd - * a function to select a duration for each item emitted by the source {@code Publisher}, used to + * a function to select a duration for each item emitted by the current {@code Flowable}, used to * determine overlap * @param rightEnd * a function to select a duration for each item emitted by the {@code right} {@code Publisher}, used to * determine overlap * @param resultSelector - * a function that computes an item to be emitted by the resulting {@code Publisher} for any two + * a function that computes an item to be emitted by the resulting {@code Flowable} for any two * overlapping items emitted by the two {@code Publisher}s - * @return a {@code Flowable} that emits items correlating to items emitted by the source {@code Publisher}s that have - * overlapping durations + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other}, {@code leftEnd}, {@code rightEnd} or {@code resultSelector} is {@code null} * @see ReactiveX operators documentation: Join */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable join( + public final <@NonNull TRight, @NonNull TLeftEnd, @NonNull TRightEnd, @NonNull R> Flowable join( @NonNull Publisher other, - @NonNull Function> leftEnd, - @NonNull Function> rightEnd, + @NonNull Function> leftEnd, + @NonNull Function> rightEnd, @NonNull BiFunction resultSelector) { Objects.requireNonNull(other, "other is null"); Objects.requireNonNull(leftEnd, "leftEnd is null"); @@ -11231,16 +11810,16 @@ public final Flowable join( * Returns a {@link Maybe} that emits the last item emitted by this {@code Flowable} or completes if * this {@code Flowable} is empty. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@link Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure).
*
Scheduler:
*
{@code lastElement} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a new {@code Maybe} instance + * @return the new {@code Maybe} instance * @see ReactiveX operators documentation: Last */ @CheckReturnValue @@ -11255,18 +11834,19 @@ public final Maybe lastElement() { * Returns a {@link Single} that emits only the last item emitted by this {@code Flowable}, or a default item * if this {@code Flowable} completes without emitting any items. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@link Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure).
*
Scheduler:
*
{@code last} does not operate by default on a particular {@link Scheduler}.
*
* * @param defaultItem - * the default item to emit if the source {@code Publisher} is empty + * the default item to emit if the current {@code Flowable} is empty * @return the new {@code Single} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX operators documentation: Last */ @CheckReturnValue @@ -11274,7 +11854,7 @@ public final Maybe lastElement() { @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) public final Single last(@NonNull T defaultItem) { - Objects.requireNonNull(defaultItem, "defaultItem"); + Objects.requireNonNull(defaultItem, "defaultItem is null"); return RxJavaPlugins.onAssembly(new FlowableLastSingle<>(this, defaultItem)); } @@ -11285,7 +11865,7 @@ public final Single last(@NonNull T defaultItem) { * *
*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@link Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure).
*
Scheduler:
*
{@code lastOrError} does not operate by default on a particular {@link Scheduler}.
@@ -11445,6 +12025,7 @@ public final Single lastOrError() { * a {@code Subscriber} with custom behavior to be used as the consumer for the current * {@code Flowable}. * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code lifter} is {@code null} * @see RxJava wiki: Writing operators * @see #compose(FlowableTransformer) */ @@ -11452,19 +12033,19 @@ public final Single lastOrError() { @NonNull @BackpressureSupport(BackpressureKind.SPECIAL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable lift(@NonNull FlowableOperator lifter) { + public final <@NonNull R> Flowable lift(@NonNull FlowableOperator lifter) { Objects.requireNonNull(lifter, "lifter is null"); return RxJavaPlugins.onAssembly(new FlowableLift<>(this, lifter)); } /** - * Returns a {@code Flowable} that applies a specified function to each item emitted by the source {@link Publisher} and + * Returns a {@code Flowable} that applies a specified function to each item emitted by the current {@code Flowable} and * emits the results of these function applications. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code map} does not operate by default on a particular {@link Scheduler}.
@@ -11472,9 +12053,9 @@ public final Flowable lift(@NonNull FlowableOperator the output type * @param mapper - * a function to apply to each item emitted by the {@code Publisher} - * @return a {@code Flowable} that emits the items from the source {@code Publisher}, transformed by the specified - * function + * a function to apply to each item emitted by the current {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: Map * @see #mapOptional(Function) */ @@ -11488,20 +12069,19 @@ public final Flowable lift(@NonNull FlowableOperatorand notifications from the source - * {@link Publisher} into emissions marked with their original types within {@link Notification} objects. + * Returns a {@code Flowable} that represents all of the emissions and notifications from the current + * {@code Flowable} into emissions marked with their original types within {@link Notification} objects. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and expects it from the source {@code Publisher}. + *
The operator honors backpressure from downstream and expects it from the current {@code Flowable}. * If this expectation is violated, the operator may throw an {@link IllegalStateException}.
*
Scheduler:
*
{@code materialize} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code Flowable} that emits items that are the result of materializing the items and notifications - * of the source {@code Publisher} + * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: Materialize * @see #dematerialize(Function) */ @@ -11516,7 +12096,7 @@ public final Flowable> materialize() { /** * Flattens this and another {@link Publisher} into a single {@code Publisher}, without any transformation. *

- * + * *

* You can combine items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by * using the {@code mergeWith} method. @@ -11530,7 +12110,8 @@ public final Flowable> materialize() { * * @param other * a {@code Publisher} to be merged - * @return a {@code Flowable} that emits all of the items emitted by the source {@code Publisher}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: Merge */ @CheckReturnValue @@ -11545,7 +12126,7 @@ public final Flowable mergeWith(@NonNull Publisher other) { /** * Merges the sequence of items of this {@code Flowable} with the success value of the other {@link SingleSource}. *

- * + * *

* The success value of the other {@code SingleSource} can get interleaved at any point of this * {@code Flowable} sequence. @@ -11559,6 +12140,7 @@ public final Flowable mergeWith(@NonNull Publisher other) { *

History: 2.1.10 - experimental * @param other the {@code SingleSource} whose success value to merge with * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -11574,7 +12156,7 @@ public final Flowable mergeWith(@NonNull SingleSource other) { * Merges the sequence of items of this {@code Flowable} with the success value of the other {@link MaybeSource} * or waits for both to complete normally if the {@code MaybeSource} is empty. *

- * + * *

* The success value of the other {@code MaybeSource} can get interleaved at any point of this * {@code Flowable} sequence. @@ -11588,6 +12170,7 @@ public final Flowable mergeWith(@NonNull SingleSource other) { *

History: 2.1.10 - experimental * @param other the {@code MaybeSource} which provides a success value to merge with or completes * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -11603,10 +12186,10 @@ public final Flowable mergeWith(@NonNull MaybeSource other) { * Relays the items of this {@code Flowable} and completes only when the other {@link CompletableSource} completes * as well. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@link Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code mergeWith} does not operate by default on a particular {@link Scheduler}.
@@ -11614,6 +12197,7 @@ public final Flowable mergeWith(@NonNull MaybeSource other) { *

History: 2.1.10 - experimental * @param other the {@code CompletableSource} to await for completion * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -11626,13 +12210,13 @@ public final Flowable mergeWith(@NonNull CompletableSource other) { } /** - * Modifies a {@link Publisher} to perform its emissions and notifications on a specified {@link Scheduler}, + * Signals the items and terminal signals of the current {@code Flowable} on the specified {@link Scheduler}, * asynchronously with a bounded buffer of {@link #bufferSize()} slots. * *

Note that {@code onError} notifications will cut ahead of {@code onNext} notifications on the emission thread if {@code Scheduler} is truly * asynchronous. If strict event ordering is required, consider using the {@link #observeOn(Scheduler, boolean)} overload. *

- * + * *

* This operator keeps emitting as many signals as it can on the given {@code Scheduler}'s Worker thread, * which may result in a longer than expected occupation of this thread. In other terms, @@ -11640,7 +12224,7 @@ public final Flowable mergeWith(@NonNull CompletableSource other) { * If such fairness and signal/work interleaving is preferred, use the delay operator with zero time instead. *

*
Backpressure:
- *
This operator honors backpressure from downstream and expects it from the source {@code Publisher}. Violating this + *
This operator honors backpressure from downstream and expects it from the current {@code Flowable}. Violating this * expectation will lead to {@link MissingBackpressureException}. This is the most common operator where the exception * pops up; look for sources up the chain that don't support backpressure, * such as {@link #interval(long, TimeUnit)}, {@link #timer(long, TimeUnit)}, @@ -11659,8 +12243,8 @@ public final Flowable mergeWith(@NonNull CompletableSource other) { * * @param scheduler * the {@code Scheduler} to notify {@link Subscriber}s on - * @return the source {@code Publisher} modified so that its {@code Subscriber}s are notified on the specified - * {@code Scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: ObserveOn * @see RxJava Threading Examples * @see #subscribeOn @@ -11677,10 +12261,10 @@ public final Flowable observeOn(@NonNull Scheduler scheduler) { } /** - * Modifies a {@link Publisher} to perform its emissions and notifications on a specified {@link Scheduler}, + * Signals the items and terminal signals of the current {@code Flowable} on the specified {@link Scheduler}, * asynchronously with a bounded buffer and optionally delays {@code onError} notifications. *

- * + * *

* This operator keeps emitting as many signals as it can on the given {@code Scheduler}'s Worker thread, * which may result in a longer than expected occupation of this thread. In other terms, @@ -11688,7 +12272,7 @@ public final Flowable observeOn(@NonNull Scheduler scheduler) { * If such fairness and signal/work interleaving is preferred, use the delay operator with zero time instead. *

*
Backpressure:
- *
This operator honors backpressure from downstream and expects it from the source {@code Publisher}. Violating this + *
This operator honors backpressure from downstream and expects it from the current {@code Flowable}. Violating this * expectation will lead to {@link MissingBackpressureException}. This is the most common operator where the exception * pops up; look for sources up the chain that don't support backpressure, * such as {@link #interval(long, TimeUnit)}, {@link #timer(long, TimeUnit)}, @@ -11709,10 +12293,10 @@ public final Flowable observeOn(@NonNull Scheduler scheduler) { * the {@code Scheduler} to notify {@link Subscriber}s on * @param delayError * indicates if the {@code onError} notification may not cut ahead of {@code onNext} notification on the other side of the - * scheduling boundary. If {@code true} a sequence ending in {@code onError} will be replayed in the same order as was received + * scheduling boundary. If {@code true}, a sequence ending in {@code onError} will be replayed in the same order as was received * from upstream - * @return the source {@code Publisher} modified so that its {@code Subscriber}s are notified on the specified - * {@code Scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: ObserveOn * @see RxJava Threading Examples * @see #subscribeOn @@ -11729,10 +12313,10 @@ public final Flowable observeOn(@NonNull Scheduler scheduler, boolean delayEr } /** - * Modifies a {@link Publisher} to perform its emissions and notifications on a specified {@link Scheduler}, + * Signals the items and terminal signals of the current {@code Flowable} on the specified {@link Scheduler}, * asynchronously with a bounded buffer of configurable size and optionally delays {@code onError} notifications. *

- * + * *

* This operator keeps emitting as many signals as it can on the given {@code Scheduler}'s Worker thread, * which may result in a longer than expected occupation of this thread. In other terms, @@ -11740,7 +12324,7 @@ public final Flowable observeOn(@NonNull Scheduler scheduler, boolean delayEr * If such fairness and signal/work interleaving is preferred, use the delay operator with zero time instead. *

*
Backpressure:
- *
This operator honors backpressure from downstream and expects it from the source {@code Publisher}. Violating this + *
This operator honors backpressure from downstream and expects it from the current {@code Flowable}. Violating this * expectation will lead to {@link MissingBackpressureException}. This is the most common operator where the exception * pops up; look for sources up the chain that don't support backpressure, * such as {@link #interval(long, TimeUnit)}, {@link #timer(long, TimeUnit)}, @@ -11761,11 +12345,12 @@ public final Flowable observeOn(@NonNull Scheduler scheduler, boolean delayEr * the {@code Scheduler} to notify {@link Subscriber}s on * @param delayError * indicates if the {@code onError} notification may not cut ahead of {@code onNext} notification on the other side of the - * scheduling boundary. If {@code true} a sequence ending in {@code onError} will be replayed in the same order as was received + * scheduling boundary. If {@code true}, a sequence ending in {@code onError} will be replayed in the same order as was received * from upstream * @param bufferSize the size of the buffer. - * @return the source {@code Publisher} modified so that its {@code Subscriber}s are notified on the specified - * {@code Scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: ObserveOn * @see RxJava Threading Examples * @see #subscribeOn @@ -11784,12 +12369,12 @@ public final Flowable observeOn(@NonNull Scheduler scheduler, boolean delayEr } /** - * Filters the items emitted by a {@link Publisher}, only emitting those of the specified type. + * Filters the items emitted by the current {@code Flowable}, only emitting those of the specified type. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code ofType} does not operate by default on a particular {@link Scheduler}.
@@ -11797,34 +12382,39 @@ public final Flowable observeOn(@NonNull Scheduler scheduler, boolean delayEr * * @param the output type * @param clazz - * the class type to filter the items emitted by the source {@code Publisher} - * @return a {@code Flowable} that emits items from the source {@code Publisher} of type {@code clazz} + * the class type to filter the items emitted by the current {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code clazz} is {@code null} * @see ReactiveX operators documentation: Filter */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable ofType(@NonNull Class clazz) { + public final <@NonNull U> Flowable ofType(@NonNull Class clazz) { Objects.requireNonNull(clazz, "clazz is null"); return filter(Functions.isInstanceOf(clazz)).cast(clazz); } /** - * Instructs a {@link Publisher} that is emitting items faster than its {@link Subscriber} can consume them to buffer these - * items indefinitely until they can be emitted. + * Buffers an unlimited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the + * downstream to consume the items at its own place. + *

+ * *

- * + * An error from the current {@code Flowable} will cut ahead of any unconsumed item. Use {@link #onBackpressureBuffer(boolean)} + * to have the operator keep the original signal order. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an unbounded + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded * manner (i.e., not applying backpressure to it).
*
Scheduler:
*
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
*
* - * @return the source {@code Publisher} modified to buffer items to the extent system resources allow + * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: backpressure operators + * @see #onBackpressureBuffer(boolean) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @@ -11835,13 +12425,13 @@ public final Flowable onBackpressureBuffer() { } /** - * Instructs a {@link Publisher} that is emitting items faster than its {@link Subscriber} can consume them to buffer these - * items indefinitely until they can be emitted. + * Buffers an unlimited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the + * downstream to consume the items at its own place, optionally delaying an error until all buffered items have been consumed. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an unbounded + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded * manner (i.e., not applying backpressure to it).
*
Scheduler:
*
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
@@ -11850,7 +12440,7 @@ public final Flowable onBackpressureBuffer() { * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping * any buffered element - * @return the source {@code Publisher} modified to buffer items to the extent system resources allow + * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: backpressure operators */ @CheckReturnValue @@ -11862,24 +12452,29 @@ public final Flowable onBackpressureBuffer(boolean delayError) { } /** - * Instructs a {@link Publisher} that is emitting items faster than its {@link Subscriber} can consume them to buffer up to - * a given amount of items until they can be emitted. The resulting {@code Publisher} will signal - * a {@code BufferOverflowException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered - * items, and canceling the source. + * Buffers an limited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the + * downstream to consume the items at its own place, however, the resulting {@code Flowable} will signal a + * {@link MissingBackpressureException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered + * items, and canceling the flow. *

- * + * + *

+ * An error from the current {@code Flowable} will cut ahead of any unconsumed item. Use {@link #onBackpressureBuffer(int, boolean)} + * to have the operator keep the original signal order. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an unbounded + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded * manner (i.e., not applying backpressure to it).
*
Scheduler:
*
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
*
* * @param capacity number of slots available in the buffer. - * @return the source {@code Publisher} modified to buffer items up to the given capacity. + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code capacity} is non-positive * @see ReactiveX operators documentation: backpressure operators * @since 1.1.0 + * @see #onBackpressureBuffer(long, Action, BackpressureOverflowStrategy) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.ERROR) @@ -11890,15 +12485,15 @@ public final Flowable onBackpressureBuffer(int capacity) { } /** - * Instructs a {@link Publisher} that is emitting items faster than its {@link Subscriber} can consume them to buffer up to - * a given amount of items until they can be emitted. The resulting {@code Publisher} will signal - * a {@code BufferOverflowException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered - * items, and canceling the source. + * Buffers an limited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the + * downstream to consume the items at its own place, however, the resulting {@code Flowable} will signal a + * {@link MissingBackpressureException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered + * items, and canceling the flow. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an unbounded + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded * manner (i.e., not applying backpressure to it).
*
Scheduler:
*
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
@@ -11909,7 +12504,8 @@ public final Flowable onBackpressureBuffer(int capacity) { * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping * any buffered element - * @return the source {@code Publisher} modified to buffer items up to the given capacity. + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code capacity} is non-positive * @see ReactiveX operators documentation: backpressure operators * @since 1.1.0 */ @@ -11922,15 +12518,16 @@ public final Flowable onBackpressureBuffer(int capacity, boolean delayError) } /** - * Instructs a {@link Publisher} that is emitting items faster than its {@link Subscriber} can consume them to buffer up to - * a given amount of items until they can be emitted. The resulting {@code Publisher} will signal - * a {@code BufferOverflowException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered - * items, and canceling the source. + * Buffers an optionally unlimited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the + * downstream to consume the items at its own place. + * If {@code unbounded} is {@code true}, the resulting {@code Flowable} will signal a + * {@link MissingBackpressureException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered + * items, and canceling the flow. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an unbounded + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded * manner (i.e., not applying backpressure to it).
*
Scheduler:
*
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
@@ -11943,7 +12540,8 @@ public final Flowable onBackpressureBuffer(int capacity, boolean delayError) * any buffered element * @param unbounded * if {@code true}, the capacity value is interpreted as the internal "island" size of the unbounded buffer - * @return the source {@code Publisher} modified to buffer items up to the given capacity. + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code capacity} is non-positive * @see ReactiveX operators documentation: backpressure operators * @since 1.1.0 */ @@ -11953,19 +12551,20 @@ public final Flowable onBackpressureBuffer(int capacity, boolean delayError) @NonNull public final Flowable onBackpressureBuffer(int capacity, boolean delayError, boolean unbounded) { ObjectHelper.verifyPositive(capacity, "capacity"); - return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBuffer<>(this, capacity, unbounded, delayError, Functions.EMPTY_ACTION)); + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBuffer<>(this, capacity, unbounded, delayError, Functions.EMPTY_ACTION, Functions.emptyConsumer())); } /** - * Instructs a {@link Publisher} that is emitting items faster than its {@link Subscriber} can consume them to buffer up to - * a given amount of items until they can be emitted. The resulting {@code Publisher} will signal - * a {@code BufferOverflowException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered - * items, canceling the source, and notifying the producer with {@code onOverflow}. + * Buffers an optionally unlimited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the + * downstream to consume the items at its own place. + * If {@code unbounded} is {@code true}, the resulting {@code Flowable} will signal a + * {@link MissingBackpressureException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered + * items, canceling the flow and calling the {@code onOverflow} action. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an unbounded + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded * manner (i.e., not applying backpressure to it).
*
Scheduler:
*
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
@@ -11978,9 +12577,12 @@ public final Flowable onBackpressureBuffer(int capacity, boolean delayError, * any buffered element * @param unbounded * if {@code true}, the capacity value is interpreted as the internal "island" size of the unbounded buffer - * @param onOverflow action to execute if an item needs to be buffered, but there are no available slots. Null is allowed. - * @return the source {@code Publisher} modified to buffer items up to the given capacity + * @param onOverflow action to execute if an item needs to be buffered, but there are no available slots. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onOverflow} is {@code null} + * @throws IllegalArgumentException if {@code capacity} is non-positive * @see ReactiveX operators documentation: backpressure operators + * @see #onBackpressureBuffer(int, boolean, boolean, Action, Consumer) * @since 1.1.0 */ @CheckReturnValue @@ -11991,19 +12593,63 @@ public final Flowable onBackpressureBuffer(int capacity, boolean delayError, @NonNull Action onOverflow) { Objects.requireNonNull(onOverflow, "onOverflow is null"); ObjectHelper.verifyPositive(capacity, "capacity"); - return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBuffer<>(this, capacity, unbounded, delayError, onOverflow)); + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBuffer<>(this, capacity, unbounded, delayError, onOverflow, Functions.emptyConsumer())); + } + + /** + * Buffers an optionally unlimited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the + * downstream to consume the items at its own place. + * If {@code unbounded} is {@code true}, the resulting {@code Flowable} will signal a + * {@link MissingBackpressureException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered + * items, canceling the flow and calling the {@code onOverflow} action. + *

+ * + *

+ *
Backpressure:
+ *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded + * manner (i.e., not applying backpressure to it).
+ *
Scheduler:
+ *
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param capacity number of slots available in the buffer. + * @param delayError + * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been + * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping + * any buffered element + * @param unbounded + * if {@code true}, the capacity value is interpreted as the internal "island" size of the unbounded buffer + * @param onOverflow action to execute if an item needs to be buffered, but there are no available slots. + * @param onDropped the {@link Consumer} to be called with the item that could not be buffered due to capacity constraints. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onOverflow} or {@code onDropped} is {@code null} + * @throws IllegalArgumentException if {@code capacity} is non-positive + * @see ReactiveX operators documentation: backpressure operators + * @since 3.1.7 + */ + @CheckReturnValue + @NonNull + @BackpressureSupport(BackpressureKind.SPECIAL) + @SchedulerSupport(SchedulerSupport.NONE) + @Experimental + public final Flowable onBackpressureBuffer(int capacity, boolean delayError, boolean unbounded, + @NonNull Action onOverflow, @NonNull Consumer onDropped) { + Objects.requireNonNull(onOverflow, "onOverflow is null"); + Objects.requireNonNull(onDropped, "onDropped is null"); + ObjectHelper.verifyPositive(capacity, "capacity"); + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBuffer<>(this, capacity, unbounded, delayError, onOverflow, onDropped)); } /** - * Instructs a {@link Publisher} that is emitting items faster than its {@link Subscriber} can consume them to buffer up to - * a given amount of items until they can be emitted. The resulting {@code Publisher} will signal - * a {@code BufferOverflowException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered - * items, canceling the source, and notifying the producer with {@code onOverflow}. + * Buffers an limited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the + * downstream to consume the items at its own place, however, the resulting {@code Flowable} will signal a + * {@link MissingBackpressureException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered + * items, canceling the flow and calling the {@code onOverflow} action. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an unbounded + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded * manner (i.e., not applying backpressure to it).
*
Scheduler:
*
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
@@ -12011,7 +12657,9 @@ public final Flowable onBackpressureBuffer(int capacity, boolean delayError, * * @param capacity number of slots available in the buffer. * @param onOverflow action to execute if an item needs to be buffered, but there are no available slots. Null is allowed. - * @return the source {@code Publisher} modified to buffer items up to the given capacity + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onOverflow} is {@code null} + * @throws IllegalArgumentException if {@code capacity} is non-positive * @see ReactiveX operators documentation: backpressure operators * @since 1.1.0 */ @@ -12024,143 +12672,365 @@ public final Flowable onBackpressureBuffer(int capacity, @NonNull Action onOv } /** - * Instructs a {@link Publisher} that is emitting items faster than its {@link Subscriber} can consume them to buffer up to - * a given amount of items until they can be emitted. The resulting {@code Publisher} will behave as determined - * by {@code overflowStrategy} if the buffer capacity is exceeded. - * + * Buffers an optionally unlimited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the + * downstream to consume the items at its own place. + * The resulting {@code Flowable} will behave as determined by {@code overflowStrategy} if the buffer capacity is exceeded: *
    - *
  • {@code BackpressureOverflow.Strategy.ON_OVERFLOW_ERROR} (default) will call {@code onError} dropping all undelivered items, + *
  • {@link BackpressureOverflowStrategy#ERROR} (default) will call {@code onError} dropping all undelivered items, * canceling the source, and notifying the producer with {@code onOverflow}.
  • - *
  • {@code BackpressureOverflow.Strategy.ON_OVERFLOW_DROP_LATEST} will drop any new items emitted by the producer while + *
  • {@link BackpressureOverflowStrategy#DROP_LATEST} will drop any new items emitted by the producer while * the buffer is full, without generating any {@code onError}. Each drop will, however, invoke {@code onOverflow} * to signal the overflow to the producer.
  • - *
  • {@code BackpressureOverflow.Strategy.ON_OVERFLOW_DROP_OLDEST} will drop the oldest items in the buffer in order to make - * room for newly emitted ones. Overflow will not generate an{@code onError}, but each drop will invoke + *
  • {@link BackpressureOverflowStrategy#DROP_OLDEST} will drop the oldest items in the buffer in order to make + * room for newly emitted ones. Overflow will not generate an {@code onError}, but each drop will invoke * {@code onOverflow} to signal the overflow to the producer.
  • *
* *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an unbounded + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded * manner (i.e., not applying backpressure to it).
*
Scheduler:
*
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
*
* * @param capacity number of slots available in the buffer. - * @param onOverflow action to execute if an item needs to be buffered, but there are no available slots. Null is allowed. - * @param overflowStrategy how should the {@code Publisher} react to buffer overflows. Null is not allowed. - * @return the source {@code Flowable} modified to buffer items up to the given capacity + * @param onOverflow action to execute if an item needs to be buffered, but there are no available slots, {@code null} is allowed. + * @param overflowStrategy how should the resulting {@code Flowable} react to buffer overflows, {@code null} is not allowed. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onOverflow} or {@code overflowStrategy} is {@code null} + * @throws IllegalArgumentException if {@code capacity} is non-positive * @see ReactiveX operators documentation: backpressure operators + * @see #onBackpressureBuffer(long, Action, BackpressureOverflowStrategy) * @since 2.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.SPECIAL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable onBackpressureBuffer(long capacity, @NonNull Action onOverflow, @NonNull BackpressureOverflowStrategy overflowStrategy) { + public final Flowable onBackpressureBuffer(long capacity, @Nullable Action onOverflow, @NonNull BackpressureOverflowStrategy overflowStrategy) { + Objects.requireNonNull(overflowStrategy, "overflowStrategy is null"); + ObjectHelper.verifyPositive(capacity, "capacity"); + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBufferStrategy<>(this, capacity, onOverflow, overflowStrategy, null)); + } + + /** + * Buffers an optionally unlimited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the + * downstream to consume the items at its own place. + * The resulting {@code Flowable} will behave as determined by {@code overflowStrategy} if the buffer capacity is exceeded: + *
    + *
  • {@link BackpressureOverflowStrategy#ERROR} (default) will call {@code onError} dropping all undelivered items, + * canceling the source, and notifying the producer with {@code onOverflow}.
  • + *
  • {@link BackpressureOverflowStrategy#DROP_LATEST} will drop any new items emitted by the producer while + * the buffer is full, without generating any {@code onError}. Each drop will, however, invoke {@code onOverflow} + * to signal the overflow to the producer.
  • + *
  • {@link BackpressureOverflowStrategy#DROP_OLDEST} will drop the oldest items in the buffer in order to make + * room for newly emitted ones. Overflow will not generate an {@code onError}, but each drop will invoke + * {@code onOverflow} to signal the overflow to the producer.
  • + *
+ * + *

+ * + *

+ *
Backpressure:
+ *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded + * manner (i.e., not applying backpressure to it).
+ *
Scheduler:
+ *
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param capacity number of slots available in the buffer. + * @param onOverflow action to execute if an item needs to be buffered, but there are no available slots, {@code null} is allowed. + * @param overflowStrategy how should the resulting {@code Flowable} react to buffer overflows, {@code null} is not allowed. + * @param onDropped the {@link Consumer} to be called with the item that could not be buffered due to capacity constraints. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onOverflow}, {@code overflowStrategy} or {@code onDropped} is {@code null} + * @throws IllegalArgumentException if {@code capacity} is non-positive + * @see ReactiveX operators documentation: backpressure operators + * @since 3.1.7 + */ + @CheckReturnValue + @NonNull + @BackpressureSupport(BackpressureKind.SPECIAL) + @SchedulerSupport(SchedulerSupport.NONE) + @Experimental + public final Flowable onBackpressureBuffer(long capacity, @Nullable Action onOverflow, @NonNull BackpressureOverflowStrategy overflowStrategy, @NonNull Consumer onDropped) { Objects.requireNonNull(overflowStrategy, "overflowStrategy is null"); + Objects.requireNonNull(onDropped, "onDropped is null"); ObjectHelper.verifyPositive(capacity, "capacity"); - return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBufferStrategy<>(this, capacity, onOverflow, overflowStrategy)); + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBufferStrategy<>(this, capacity, onOverflow, overflowStrategy, onDropped)); + } + /** + * Drops items from the current {@code Flowable} if the downstream is not ready to receive new items (indicated + * by a lack of {@link Subscription#request(long)} calls from it). + *

+ * + *

+ * If the downstream request count hits 0 then the resulting {@code Flowable} will refrain from calling {@code onNext} until + * the {@link Subscriber} invokes {@code request(n)} again to increase the request count. + *

+ *
Backpressure:
+ *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded + * manner (i.e., not applying backpressure to it).
+ *
Scheduler:
+ *
{@code onBackpressureDrop} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @return the new {@code Flowable} instance + * @see ReactiveX operators documentation: backpressure operators + */ + @CheckReturnValue + @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Flowable onBackpressureDrop() { + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureDrop<>(this)); + } + + /** + * Drops items from the current {@code Flowable} if the downstream is not ready to receive new items (indicated + * by a lack of {@link Subscription#request(long)} calls from it) and calls the given {@link Consumer} with such + * dropped items. + *

+ * + *

+ * If the downstream request count hits 0 then the resulting {@code Flowable} will refrain from calling {@code onNext} until + * the {@link Subscriber} invokes {@code request(n)} again to increase the request count. + *

+ *
Backpressure:
+ *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded + * manner (i.e., not applying backpressure to it).
+ *
Scheduler:
+ *
{@code onBackpressureDrop} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param onDrop the action to invoke for each item dropped, should be fast and should never block. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code onDrop} is {@code null} + * @see ReactiveX operators documentation: backpressure operators + * @since 1.1.0 + */ + @CheckReturnValue + @NonNull + @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) + @SchedulerSupport(SchedulerSupport.NONE) + public final Flowable onBackpressureDrop(@NonNull Consumer onDrop) { + Objects.requireNonNull(onDrop, "onDrop is null"); + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureDrop<>(this, onDrop)); + } + + /** + * Drops all but the latest item emitted by the current {@code Flowable} if the downstream is not ready to receive + * new items (indicated by a lack of {@link Subscription#request(long)} calls from it) and emits this latest + * item when the downstream becomes ready. + *

+ * + *

+ * Its behavior is logically equivalent to {@code blockingLatest()} with the exception that + * the downstream is not blocking while requesting more values. + *

+ * Note that if the current {@code Flowable} does support backpressure, this operator ignores that capability + * and doesn't propagate any backpressure requests from downstream. + *

+ * Note that due to the nature of how backpressure requests are propagated through subscribeOn/observeOn, + * requesting more than 1 from downstream doesn't guarantee a continuous delivery of {@code onNext} events. + *

+ *
Backpressure:
+ *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded + * manner (i.e., not applying backpressure to it).
+ *
Scheduler:
+ *
{@code onBackpressureLatest} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @return the new {@code Flowable} instance + * @since 1.1.0 + */ + @CheckReturnValue + @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Flowable onBackpressureLatest() { + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureLatest<>(this, null)); + } + + /** + * Drops all but the latest item emitted by the current {@code Flowable} if the downstream is not ready to receive + * new items (indicated by a lack of {@link Subscription#request(long)} calls from it) and emits this latest + * item when the downstream becomes ready. + *

+ * + *

+ * Its behavior is logically equivalent to {@code blockingLatest()} with the exception that + * the downstream is not blocking while requesting more values. + *

+ * Note that if the current {@code Flowable} does support backpressure, this operator ignores that capability + * and doesn't propagate any backpressure requests from downstream. + *

+ * Note that due to the nature of how backpressure requests are propagated through subscribeOn/observeOn, + * requesting more than 1 from downstream doesn't guarantee a continuous delivery of {@code onNext} events. + *

+ *
Backpressure:
+ *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded + * manner (i.e., not applying backpressure to it).
+ *
Scheduler:
+ *
{@code onBackpressureLatest} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param onDropped + * called with the current entry when it has been replaced by a new one + * @throws NullPointerException if {@code onDropped} is {@code null} + * @return the new {@code Flowable} instance + * @since 3.1.7 + */ + @CheckReturnValue + @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + @Experimental + public final Flowable onBackpressureLatest(@NonNull Consumer onDropped) { + Objects.requireNonNull(onDropped, "onDropped is null"); + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureLatest<>(this, onDropped)); + } + + /** + * Reduces a sequence of two not emitted values via a function into a single value if the downstream is not ready to receive + * new items (indicated by a lack of {@link Subscription#request(long)} calls from it) and emits this latest + * item when the downstream becomes ready. + *

+ * + *

+ * Note that if the current {@code Flowable} does support backpressure, this operator ignores that capability + * and doesn't propagate any backpressure requests from downstream. + *

+ * Note that due to the nature of how backpressure requests are propagated through subscribeOn/observeOn, + * requesting more than 1 from downstream doesn't guarantee a continuous delivery of {@code onNext} events. + *

+ *
Backpressure:
+ *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded + * manner (i.e., not applying backpressure to it).
+ *
Scheduler:
+ *
{@code onBackpressureReduce} does not operate by default on a particular {@link Scheduler}.
+ *
+ *

History: 3.0.9 - experimental + * @param reducer the bi-function to call when there is more than one non-emitted value to downstream, + * the first argument of the bi-function is previous item and the second one is currently + * emitting from upstream + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code reducer} is {@code null} + * @since 3.1.0 + * @see #onBackpressureReduce(Supplier, BiFunction) + */ + @CheckReturnValue + @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Flowable onBackpressureReduce(@NonNull BiFunction reducer) { + Objects.requireNonNull(reducer, "reducer is null"); + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureReduce<>(this, reducer)); } /** - * Instructs a {@link Publisher} that is emitting items faster than its {@link Subscriber} can consume them to discard, - * rather than emit, those items that its {@code Subscriber} is not prepared to observe. + * Reduces upstream values into an aggregate value, provided by a supplier and combined via a reducer function, + * while the downstream is not ready to receive items, then emits this aggregate value when the downstream becomes ready. + *

+ * *

- * + * Note that even if the downstream is ready to receive an item, the upstream item will always be aggregated into the output type, + * calling both the supplier and the reducer to produce the output value. *

- * If the downstream request count hits 0 then the {@code Publisher} will refrain from calling {@code onNext} until - * the {@code Subscriber} invokes {@code request(n)} again to increase the request count. + * Note that if the current {@code Flowable} does support backpressure, this operator ignores that capability + * and doesn't propagate any backpressure requests from downstream. + *

+ * Note that due to the nature of how backpressure requests are propagated through subscribeOn/observeOn, + * requesting more than 1 from downstream doesn't guarantee a continuous delivery of {@code onNext} events. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an unbounded + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded * manner (i.e., not applying backpressure to it).
*
Scheduler:
- *
{@code onBackpressureDrop} does not operate by default on a particular {@link Scheduler}.
+ *
{@code onBackpressureReduce} does not operate by default on a particular {@link Scheduler}.
*
- * - * @return the source {@code Publisher} modified to drop {@code onNext} notifications on overflow - * @see ReactiveX operators documentation: backpressure operators + *

History: 3.0.9 - experimental + * @param the aggregate type emitted when the downstream requests more items + * @param supplier the factory to call to create new item of type R to pass it as the first argument to {@code reducer}. + * It is called when previous returned value by {@code reducer} already sent to + * downstream or the very first update from upstream received. + * @param reducer the bi-function to call to reduce excessive updates which downstream is not ready to receive. + * The first argument of type R is the object returned by {@code supplier} or result of previous + * {@code reducer} invocation. The second argument of type T is the current update from upstream. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code supplier} or {@code reducer} is {@code null} + * @see #onBackpressureReduce(BiFunction) + * @since 3.1.0 */ @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable onBackpressureDrop() { - return RxJavaPlugins.onAssembly(new FlowableOnBackpressureDrop<>(this)); + public final <@NonNull R> Flowable onBackpressureReduce(@NonNull Supplier supplier, @NonNull BiFunction reducer) { + Objects.requireNonNull(supplier, "supplier is null"); + Objects.requireNonNull(reducer, "reducer is null"); + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureReduceWith<>(this, supplier, reducer)); } /** - * Instructs a {@link Publisher} that is emitting items faster than its {@link Subscriber} can consume them to discard, - * rather than emit, those items that its {@code Subscriber} is not prepared to observe. + * Returns a {@code Flowable} instance that if the current {@code Flowable} emits an error, it will emit an {@code onComplete} + * and swallow the throwable. *

- * - *

- * If the downstream request count hits 0 then the {@code Publisher} will refrain from calling {@code onNext} until - * the {@code Subscriber} invokes {@code request(n)} again to increase the request count. + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an unbounded - * manner (i.e., not applying backpressure to it).
+ *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure + * behavior.
*
Scheduler:
- *
{@code onBackpressureDrop} does not operate by default on a particular {@link Scheduler}.
+ *
{@code onErrorComplete} does not operate by default on a particular {@link Scheduler}.
*
- * - * @param onDrop the action to invoke for each item dropped, should be fast and should never block. - * @return the source {@code Publisher} modified to drop {@code onNext} notifications on overflow - * @see ReactiveX operators documentation: backpressure operators - * @since 1.1.0 + * @return the new {@code Flowable} instance + * @since 3.0.0 */ @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable onBackpressureDrop(@NonNull Consumer onDrop) { - Objects.requireNonNull(onDrop, "onDrop is null"); - return RxJavaPlugins.onAssembly(new FlowableOnBackpressureDrop<>(this, onDrop)); + @BackpressureSupport(BackpressureKind.PASS_THROUGH) + @NonNull + public final Flowable onErrorComplete() { + return onErrorComplete(Functions.alwaysTrue()); } /** - * Instructs a {@link Publisher} that is emitting items faster than its {@link Subscriber} can consume them to - * hold onto the latest value and emit that on request. - *

- * - *

- * Its behavior is logically equivalent to {@code blockingLatest()} with the exception that - * the downstream is not blocking while requesting more values. - *

- * Note that if the upstream {@code Publisher} does support backpressure, this operator ignores that capability - * and doesn't propagate any backpressure requests from downstream. + * Returns a {@code Flowable} instance that if the current {@code Flowable} emits an error and the predicate returns + * {@code true}, it will emit an {@code onComplete} and swallow the throwable. *

- * Note that due to the nature of how backpressure requests are propagated through subscribeOn/observeOn, - * requesting more than 1 from downstream doesn't guarantee a continuous delivery of {@code onNext} events. + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an unbounded - * manner (i.e., not applying backpressure to it).
+ *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure + * behavior.
*
Scheduler:
- *
{@code onBackpressureLatest} does not operate by default on a particular {@link Scheduler}.
+ *
{@code onErrorComplete} does not operate by default on a particular {@link Scheduler}.
*
- * - * @return the source {@code Publisher} modified so that it emits the most recently-received item upon request - * @since 1.1.0 + * @param predicate the predicate to call when an {@link Throwable} is emitted which should return {@code true} + * if the {@code Throwable} should be swallowed and replaced with an {@code onComplete}. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code predicate} is {@code null} + * @since 3.0.0 */ @CheckReturnValue - @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) + @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable onBackpressureLatest() { - return RxJavaPlugins.onAssembly(new FlowableOnBackpressureLatest<>(this)); + public final Flowable onErrorComplete(@NonNull Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + + return RxJavaPlugins.onAssembly(new FlowableOnErrorComplete<>(this, predicate)); } /** - * Instructs a {@link Publisher} to pass control to another {@code Publisher} rather than invoking - * {@link Subscriber#onError onError} if it encounters an error. + * Resumes the flow with a {@link Publisher} returned for the failure {@link Throwable} of the current {@code Flowable} by a + * function instead of signaling the error via {@code onError}. *

- * + * *

* By default, when a {@code Publisher} encounters an error that prevents it from emitting the expected item to * its {@link Subscriber}, the {@code Publisher} invokes its {@code Subscriber}'s {@code onError} method, and then quits @@ -12179,32 +13049,33 @@ public final Flowable onBackpressureLatest() { *

The operator honors backpressure from downstream. This and the resuming {@code Publisher}s * are expected to honor backpressure as well. * If any of them violate this expectation, the operator may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes or + * {@link IllegalStateException} when the current {@code Flowable} completes or * a {@link MissingBackpressureException} is signaled somewhere downstream.
*
Scheduler:
*
{@code onErrorResumeNext} does not operate by default on a particular {@link Scheduler}.
*
* - * @param resumeFunction - * a function that returns a {@code Publisher} that will take over if the source {@code Publisher} encounters + * @param fallbackSupplier + * a function that returns a {@code Publisher} that will take over if the current {@code Flowable} encounters * an error - * @return the original {@code Publisher}, with appropriately modified behavior + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code fallbackSupplier} is {@code null} * @see ReactiveX operators documentation: Catch */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable onErrorResumeNext(@NonNull Function> resumeFunction) { - Objects.requireNonNull(resumeFunction, "resumeFunction is null"); - return RxJavaPlugins.onAssembly(new FlowableOnErrorNext<>(this, resumeFunction)); + public final Flowable onErrorResumeNext(@NonNull Function> fallbackSupplier) { + Objects.requireNonNull(fallbackSupplier, "fallbackSupplier is null"); + return RxJavaPlugins.onAssembly(new FlowableOnErrorNext<>(this, fallbackSupplier)); } /** - * Instructs a {@link Publisher} to pass control to another {@code Publisher} rather than invoking - * {@link Subscriber#onError onError} if it encounters an error. + * Resumes the flow with the given {@link Publisher} when the current {@code Flowable} fails instead of + * signaling the error via {@code onError}. *

- * + * *

* By default, when a {@code Publisher} encounters an error that prevents it from emitting the expected item to * its {@link Subscriber}, the {@code Publisher} invokes its {@code Subscriber}'s {@code onError} method, and then quits @@ -12223,34 +13094,35 @@ public final Flowable onErrorResumeNext(@NonNull FunctionThe operator honors backpressure from downstream. This and the resuming {@code Publisher}s * are expected to honor backpressure as well. * If any of them violate this expectation, the operator may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes or + * {@link IllegalStateException} when the current {@code Flowable} completes or * {@link MissingBackpressureException} is signaled somewhere downstream.

*
Scheduler:
*
{@code onErrorResumeWith} does not operate by default on a particular {@link Scheduler}.
*
* - * @param next - * the next {@code Publisher} source that will take over if the source {@code Publisher} encounters + * @param fallback + * the next {@code Publisher} source that will take over if the current {@code Flowable} encounters * an error - * @return the original {@code Publisher}, with appropriately modified behavior + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code fallback} is {@code null} * @see ReactiveX operators documentation: Catch */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable onErrorResumeWith(@NonNull Publisher next) { - Objects.requireNonNull(next, "next is null"); - return onErrorResumeNext(Functions.justFunction(next)); + public final Flowable onErrorResumeWith(@NonNull Publisher fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return onErrorResumeNext(Functions.justFunction(fallback)); } /** - * Instructs a {@link Publisher} to emit an item (returned by a specified function) rather than invoking - * {@link Subscriber#onError onError} if it encounters an error. + * Ends the flow with a last item returned by a function for the {@link Throwable} error signaled by the current + * {@code Flowable} instead of signaling the error via {@code onError}. *

- * + * *

- * By default, when a {@code Publisher} encounters an error that prevents it from emitting the expected item to + * By default, when a {@link Publisher} encounters an error that prevents it from emitting the expected item to * its {@link Subscriber}, the {@code Publisher} invokes its {@code Subscriber}'s {@code onError} method, and then quits * without invoking any more of its {@code Subscriber}'s methods. The {@code onErrorReturn} method changes this * behavior. If you pass a function ({@code resumeFunction}) to a {@code Publisher}'s {@code onErrorReturn} @@ -12261,36 +13133,36 @@ public final Flowable onErrorResumeWith(@NonNull Publisher next) * encountered. *

*
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s is expected to honor + *
The operator honors backpressure from downstream. The current {@code Flowable} is expected to honor * backpressure as well. If it this expectation is violated, the operator may throw - * {@link IllegalStateException} when the source {@code Publisher} completes or + * {@link IllegalStateException} when the current {@code Flowable} completes or * {@link MissingBackpressureException} is signaled somewhere downstream.
*
Scheduler:
*
{@code onErrorReturn} does not operate by default on a particular {@link Scheduler}.
*
* - * @param valueSupplier + * @param itemSupplier * a function that returns a single value that will be emitted along with a regular {@code onComplete} in case * the current {@code Flowable} signals an {@code onError} event - * @return the original {@code Publisher} with appropriately modified behavior + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code itemSupplier} is {@code null} * @see ReactiveX operators documentation: Catch */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable onErrorReturn(@NonNull Function valueSupplier) { - Objects.requireNonNull(valueSupplier, "valueSupplier is null"); - return RxJavaPlugins.onAssembly(new FlowableOnErrorReturn<>(this, valueSupplier)); + public final Flowable onErrorReturn(@NonNull Function itemSupplier) { + Objects.requireNonNull(itemSupplier, "itemSupplier is null"); + return RxJavaPlugins.onAssembly(new FlowableOnErrorReturn<>(this, itemSupplier)); } /** - * Instructs a {@link Publisher} to emit an item (returned by a specified function) rather than invoking - * {@link Subscriber#onError onError} if it encounters an error. + * Ends the flow with the given last item when the current {@code Flowable} fails instead of signaling the error via {@code onError}. *

- * + * *

- * By default, when a {@code Publisher} encounters an error that prevents it from emitting the expected item to + * By default, when a {@link Publisher} encounters an error that prevents it from emitting the expected item to * its {@link Subscriber}, the {@code Publisher} invokes its {@code Subscriber}'s {@code onError} method, and then quits * without invoking any more of its {@code Subscriber}'s methods. The {@code onErrorReturn} method changes this * behavior. If you pass a function ({@code resumeFunction}) to a {@code Publisher}'s {@code onErrorReturn} @@ -12301,9 +13173,9 @@ public final Flowable onErrorReturn(@NonNull Function *

Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s is expected to honor + *
The operator honors backpressure from downstream. The current {@code Flowable} is expected to honor * backpressure as well. If it this expectation is violated, the operator may throw - * {@link IllegalStateException} when the source {@code Publisher} completes or + * {@link IllegalStateException} when the current {@code Flowable} completes or * {@link MissingBackpressureException} is signaled somewhere downstream.
*
Scheduler:
*
{@code onErrorReturnItem} does not operate by default on a particular {@link Scheduler}.
@@ -12312,7 +13184,8 @@ public final Flowable onErrorReturn(@NonNull FunctionReactiveX operators documentation: Catch */ @CheckReturnValue @@ -12329,12 +13202,12 @@ public final Flowable onErrorReturnItem(@NonNull T item) { * the sequence is terminated or downstream cancels. *
*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@link Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code onTerminateDetach} does not operate by default on a particular {@link Scheduler}.
*
- * @return a {@code Flowable} which {@code null}s out references to the upstream producer and downstream {@code Subscriber} if + * @return the new {@code Flowable} instance * the sequence is terminated or downstream cancels * @since 2.0 */ @@ -12397,6 +13270,7 @@ public final ParallelFlowable parallel() { *

History: 2.0.5 - experimental; 2.1 - beta * @param parallelism the number of 'rails' to use * @return the new {@link ParallelFlowable} instance + * @throws IllegalArgumentException if {@code parallelism} is non-positive * @since 2.2 */ @BackpressureSupport(BackpressureKind.FULL) @@ -12404,7 +13278,6 @@ public final ParallelFlowable parallel() { @CheckReturnValue @NonNull public final ParallelFlowable parallel(int parallelism) { - ObjectHelper.verifyPositive(parallelism, "parallelism"); return ParallelFlowable.from(this, parallelism); } @@ -12431,6 +13304,7 @@ public final ParallelFlowable parallel(int parallelism) { * @param parallelism the number of 'rails' to use * @param prefetch the number of items each 'rail' should prefetch * @return the new {@link ParallelFlowable} instance + * @throws IllegalArgumentException if {@code parallelism} or {@code prefetch} is non-positive * @since 2.2 */ @BackpressureSupport(BackpressureKind.FULL) @@ -12438,8 +13312,6 @@ public final ParallelFlowable parallel(int parallelism) { @CheckReturnValue @NonNull public final ParallelFlowable parallel(int parallelism, int prefetch) { - ObjectHelper.verifyPositive(parallelism, "parallelism"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); return ParallelFlowable.from(this, parallelism, prefetch); } @@ -12448,18 +13320,17 @@ public final ParallelFlowable parallel(int parallelism, int prefetch) { * {@link ConnectableFlowable#connect connect} method is called before it begins emitting items to those * {@link Subscriber}s that have subscribed to it. *

- * + * *

*
Backpressure:
*
The returned {@code ConnectableFlowable} honors backpressure for each of its {@code Subscriber}s - * and expects the source {@code Publisher} to honor backpressure as well. If this expectation is violated, + * and expects the current {@code Flowable} to honor backpressure as well. If this expectation is violated, * the operator will signal a {@link MissingBackpressureException} to its {@code Subscriber}s and disconnect.
*
Scheduler:
*
{@code publish} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code ConnectableFlowable} that upon connection causes the source {@code Publisher} to emit items - * to its {@code Subscriber}s + * @return the new {@code ConnectableFlowable} instance * @see ReactiveX operators documentation: Publish */ @CheckReturnValue @@ -12474,32 +13345,33 @@ public final ConnectableFlowable publish() { * Returns a {@code Flowable} that emits the results of invoking a specified selector on items emitted by a * {@link ConnectableFlowable} that shares a single subscription to the underlying sequence. *

- * + * *

*
Backpressure:
- *
The operator expects the source {@link Publisher} to honor backpressure and if this expectation is - * violated, the operator will signal a {@link MissingBackpressureException} through the {@code Publisher} - * provided to the function. Since the {@code Publisher} returned by the {@code selector} may be - * independent of the provided {@code Publisher} to the function, the output's backpressure behavior + *
The operator expects the current {@code Flowable} to honor backpressure and if this expectation is + * violated, the operator will signal a {@link MissingBackpressureException} through the {@code Flowable} + * provided to the function. Since the {@link Publisher} returned by the {@code selector} may be + * independent of the provided {@code Flowable} to the function, the output's backpressure behavior * is determined by this returned {@code Publisher}.
*
Scheduler:
*
{@code publish} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param selector * a function that can use the multicasted source sequence as many times as needed, without * causing multiple subscriptions to the source sequence. {@link Subscriber}s to the given source will * receive all notifications of the source from the time of the subscription forward. - * @return a {@code Flowable} that emits the results of invoking the selector on the items emitted by a {@code ConnectableFlowable} that shares a single subscription to the underlying sequence + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code selector} is {@code null} * @see ReactiveX operators documentation: Publish */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable publish(@NonNull Function, ? extends Publisher> selector) { + public final <@NonNull R> Flowable publish(@NonNull Function, @NonNull ? extends Publisher> selector) { return publish(selector, bufferSize()); } @@ -12507,34 +13379,36 @@ public final Flowable publish(@NonNull Function, ? ex * Returns a {@code Flowable} that emits the results of invoking a specified selector on items emitted by a * {@link ConnectableFlowable} that shares a single subscription to the underlying sequence. *

- * + * *

*
Backpressure:
- *
The operator expects the source {@link Publisher} to honor backpressure and if this expectation is - * violated, the operator will signal a {@link MissingBackpressureException} through the {@code Publisher} - * provided to the function. Since the {@code Publisher} returned by the {@code selector} may be - * independent of the provided {@code Publisher} to the function, the output's backpressure behavior + *
The operator expects the current {@code Flowable} to honor backpressure and if this expectation is + * violated, the operator will signal a {@link MissingBackpressureException} through the {@code Flowable} + * provided to the function. Since the {@link Publisher} returned by the {@code selector} may be + * independent of the provided {@code Flowable} to the function, the output's backpressure behavior * is determined by this returned {@code Publisher}.
*
Scheduler:
*
{@code publish} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param selector * a function that can use the multicasted source sequence as many times as needed, without * causing multiple subscriptions to the source sequence. {@link Subscriber}s to the given source will * receive all notifications of the source from the time of the subscription forward. * @param prefetch * the number of elements to prefetch from the current {@code Flowable} - * @return a {@code Flowable} that emits the results of invoking the selector on the items emitted by a {@code ConnectableFlowable} that shares a single subscription to the underlying sequence + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code selector} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive * @see ReactiveX operators documentation: Publish */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable publish(@NonNull Function, ? extends Publisher> selector, int prefetch) { + public final <@NonNull R> Flowable publish(@NonNull Function, @NonNull ? extends Publisher> selector, int prefetch) { Objects.requireNonNull(selector, "selector is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); return RxJavaPlugins.onAssembly(new FlowablePublishMulticast<>(this, selector, prefetch, false)); @@ -12545,11 +13419,11 @@ public final Flowable publish(@NonNull Function, ? ex * {@link ConnectableFlowable#connect connect} method is called before it begins emitting items to those * {@link Subscriber}s that have subscribed to it. *

- * + * *

*
Backpressure:
*
The returned {@code ConnectableFlowable} honors backpressure for each of its {@code Subscriber}s - * and expects the source {@code Publisher} to honor backpressure as well. If this expectation is violated, + * and expects the current {@code Flowable} to honor backpressure as well. If this expectation is violated, * the operator will signal a {@link MissingBackpressureException} to its {@code Subscriber}s and disconnect.
*
Scheduler:
*
{@code publish} does not operate by default on a particular {@link Scheduler}.
@@ -12557,8 +13431,8 @@ public final Flowable publish(@NonNull Function, ? ex * * @param bufferSize * the number of elements to prefetch from the current {@code Flowable} - * @return a {@code ConnectableFlowable} that upon connection causes the source {@code Publisher} to emit items - * to its {@code Subscriber}s + * @return the new {@code ConnectableFlowable} instance + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Publish */ @CheckReturnValue @@ -12585,7 +13459,8 @@ public final ConnectableFlowable publish(int bufferSize) { *
* * @param n the initial request amount, further request will happen after 75% of this value - * @return the {@link Publisher} that rebatches request amounts from downstream + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code n} is non-positive * @since 2.0 */ @CheckReturnValue @@ -12597,12 +13472,12 @@ public final Flowable rebatchRequests(int n) { } /** - * Returns a {@link Maybe} that applies a specified accumulator function to the first item emitted by a source - * {@link Publisher}, then feeds the result of that function along with the second item emitted by the source - * {@code Publisher} into the same function, and so on until all items have been emitted by the finite source {@code Publisher}, + * Returns a {@link Maybe} that applies a specified accumulator function to the first item emitted by the current + * {@code Flowable}, then feeds the result of that function along with the second item emitted by the current + * {@code Flowable} into the same function, and so on until all items have been emitted by the current and finite {@code Flowable}, * and emits the final result from the final call to your function as its sole item. *

- * + * *

* This technique, which is called "reduce" here, is sometimes called "aggregate," "fold," "accumulate," * "compress," or "inject" in other programming contexts. Groovy, for instance, has an {@code inject} method @@ -12620,10 +13495,10 @@ public final Flowable rebatchRequests(int n) { *

* * @param reducer - * an accumulator function to be invoked on each item emitted by the source {@code Publisher}, whose + * an accumulator function to be invoked on each item emitted by the current {@code Flowable}, whose * result will be used in the next accumulator call - * @return a {@code Maybe} that emits a single item that is the result of accumulating the items emitted by - * the source {@code Flowable} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code reducer} is {@code null} * @see ReactiveX operators documentation: Reduce * @see Wikipedia: Fold (higher-order function) */ @@ -12637,18 +13512,18 @@ public final Maybe reduce(@NonNull BiFunction reducer) { } /** - * Returns a {@link Single} that applies a specified accumulator function to the first item emitted by a source - * {@link Publisher} and a specified seed value, then feeds the result of that function along with the second item - * emitted by a {@code Publisher} into the same function, and so on until all items have been emitted by the - * finite source {@code Publisher}, emitting the final result from the final call to your function as its sole item. + * Returns a {@link Single} that applies a specified accumulator function to the first item emitted by the current + * {@code Flowable} and a specified seed value, then feeds the result of that function along with the second item + * emitted by the current {@code Flowable} into the same function, and so on until all items have been emitted by the + * current and finite {@code Flowable}, emitting the final result from the final call to your function as its sole item. *

- * + * *

* This technique, which is called "reduce" here, is sometimes called "aggregate," "fold," "accumulate," * "compress," or "inject" in other programming contexts. Groovy, for instance, has an {@code inject} method * that does a similar operation on lists. *

- * Note that the {@code seed} is shared among all subscribers to the resulting {@code Publisher} + * Note that the {@code seed} is shared among all subscribers to the resulting {@code Flowable} * and may cause problems if it is mutable. To make sure each subscriber gets its own value, defer * the application of this operator via {@link #defer(Supplier)}: *


@@ -12681,10 +13556,10 @@ public final Maybe reduce(@NonNull BiFunction reducer) {
      * @param seed
      *            the initial (seed) accumulator value
      * @param reducer
-     *            an accumulator function to be invoked on each item emitted by the source {@code Publisher}, the
+     *            an accumulator function to be invoked on each item emitted by the current {@code Flowable}, the
      *            result of which will be used in the next accumulator call
-     * @return a {@code Single} that emits a single item that is the result of accumulating the output from the
-     *         items emitted by the source {@code Publisher}
+     * @return the new {@code Single} instance
+     * @throws NullPointerException if {@code seed} or {@code reducer} is {@code null}
      * @see ReactiveX operators documentation: Reduce
      * @see Wikipedia: Fold (higher-order function)
      * @see #reduceWith(Supplier, BiFunction)
@@ -12700,13 +13575,13 @@ public final Maybe reduce(@NonNull BiFunction reducer) {
     }
 
     /**
-     * Returns a {@link Single} that applies a specified accumulator function to the first item emitted by a source
-     * {@link Publisher} and a seed value derived from calling a specified {@code seedSupplier}, then feeds the result
-     * of that function along with the second item emitted by a {@code Publisher} into the same function, and so on until
-     * all items have been emitted by the finite source {@code Publisher}, emitting the final result from the final call to your
+     * Returns a {@link Single} that applies a specified accumulator function to the first item emitted by the current
+     * {@code Flowable} and a seed value derived from calling a specified {@code seedSupplier}, then feeds the result
+     * of that function along with the second item emitted by the current {@code Flowable} into the same function, and so on until
+     * all items have been emitted by the current and finite {@code Flowable}, emitting the final result from the final call to your
      * function as its sole item.
      * 

- * + * *

* This technique, which is called "reduce" here, is sometimes called "aggregate", "fold", "accumulate", * "compress", or "inject" in other programming contexts. Groovy, for instance, has an {@code inject} method @@ -12727,10 +13602,10 @@ public final Maybe reduce(@NonNull BiFunction reducer) { * @param seedSupplier * the {@link Supplier} that provides the initial (seed) accumulator value for each individual {@link Subscriber} * @param reducer - * an accumulator function to be invoked on each item emitted by the source {@code Publisher}, the + * an accumulator function to be invoked on each item emitted by the current {@code Flowable}, the * result of which will be used in the next accumulator call - * @return a {@code Single} that emits a single item that is the result of accumulating the output from the - * items emitted by the source {@code Publisher} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code seedSupplier} or {@code reducer} is {@code null} * @see ReactiveX operators documentation: Reduce * @see Wikipedia: Fold (higher-order function) */ @@ -12745,18 +13620,18 @@ public final Maybe reduce(@NonNull BiFunction reducer) { } /** - * Returns a {@code Flowable} that repeats the sequence of items emitted by the source {@link Publisher} indefinitely. + * Returns a {@code Flowable} that repeats the sequence of items emitted by the current {@code Flowable} indefinitely. *

- * + * *

*
Backpressure:
- *
The operator honors downstream backpressure and expects the source {@code Publisher} to honor backpressure as well. + *
The operator honors downstream backpressure and expects the current {@code Flowable} to honor backpressure as well. * If this expectation is violated, the operator may throw an {@link IllegalStateException}.
*
Scheduler:
*
{@code repeat} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code Flowable} that emits the items emitted by the source {@code Publisher} repeatedly and in sequence + * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: Repeat */ @CheckReturnValue @@ -12768,25 +13643,24 @@ public final Flowable repeat() { } /** - * Returns a {@code Flowable} that repeats the sequence of items emitted by the source {@link Publisher} at most + * Returns a {@code Flowable} that repeats the sequence of items emitted by the current {@code Flowable} at most * {@code count} times. *

- * + * *

*
Backpressure:
- *
The operator honors downstream backpressure and expects the source {@code Publisher} to honor backpressure as well. + *
The operator honors downstream backpressure and expects the current {@code Flowable} to honor backpressure as well. * If this expectation is violated, the operator may throw an {@link IllegalStateException}.
*
Scheduler:
*
{@code repeat} does not operate by default on a particular {@link Scheduler}.
*
* * @param times - * the number of times the source {@code Publisher} items are repeated, a count of 0 will yield an empty + * the number of times the current {@code Flowable} items are repeated, a count of 0 will yield an empty * sequence - * @return a {@code Flowable} that repeats the sequence of items emitted by the source {@code Publisher} at most - * {@code count} times + * @return the new {@code Flowable} instance * @throws IllegalArgumentException - * if {@code count} is less than zero + * if {@code times} is less than zero * @see ReactiveX operators documentation: Repeat */ @CheckReturnValue @@ -12804,13 +13678,13 @@ public final Flowable repeat(long times) { } /** - * Returns a {@code Flowable} that repeats the sequence of items emitted by the source {@link Publisher} until + * Returns a {@code Flowable} that repeats the sequence of items emitted by the current {@code Flowable} until * the provided stop function returns {@code true}. *

- * + * *

*
Backpressure:
- *
The operator honors downstream backpressure and expects the source {@code Publisher} to honor backpressure as well. + *
The operator honors downstream backpressure and expects the current {@code Flowable} to honor backpressure as well. * If this expectation is violated, the operator may throw an {@link IllegalStateException}.
*
Scheduler:
*
{@code repeatUntil} does not operate by default on a particular {@link Scheduler}.
@@ -12834,17 +13708,17 @@ public final Flowable repeatUntil(@NonNull BooleanSupplier stop) { } /** - * Returns a {@code Flowable} that emits the same values as the source {@link Publisher} with the exception of an + * Returns a {@code Flowable} that emits the same values as the current {@code Flowable} with the exception of an * {@code onComplete}. An {@code onComplete} notification from the source will result in the emission of - * a {@code void} item to the {@code Publisher} provided as an argument to the {@code notificationHandler} - * function. If that {@code Publisher} calls {@code onComplete} or {@code onError} then {@code repeatWhen} will + * a {@code void} item to the {@code Flowable} provided as an argument to the {@code notificationHandler} + * function. If that {@link Publisher} calls {@code onComplete} or {@code onError} then {@code repeatWhen} will * call {@code onComplete} or {@code onError} on the child subscription. Otherwise, this {@code Publisher} will - * resubscribe to the source {@code Publisher}. + * resubscribe to the current {@code Flowable}. *

- * + * *

*
Backpressure:
- *
The operator honors downstream backpressure and expects the source {@code Publisher} to honor backpressure as well. + *
The operator honors downstream backpressure and expects the current {@code Flowable} to honor backpressure as well. * If this expectation is violated, the operator may throw an {@link IllegalStateException}.
*
Scheduler:
*
{@code repeatWhen} does not operate by default on a particular {@link Scheduler}.
@@ -12852,36 +13726,36 @@ public final Flowable repeatUntil(@NonNull BooleanSupplier stop) { * * @param handler * receives a {@code Publisher} of notifications with which a user can complete or error, aborting the repeat. - * @return the source {@code Publisher} modified with repeat logic + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code handler} is {@code null} * @see ReactiveX operators documentation: Repeat */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable repeatWhen(@NonNull Function, ? extends Publisher> handler) { + public final Flowable repeatWhen(@NonNull Function, @NonNull ? extends Publisher<@NonNull ?>> handler) { Objects.requireNonNull(handler, "handler is null"); return RxJavaPlugins.onAssembly(new FlowableRepeatWhen<>(this, handler)); } /** * Returns a {@link ConnectableFlowable} that shares a single subscription to the underlying {@link Publisher} - * that will replay all of its items and notifications to any future {@link Subscriber}. A Connectable - * {@code Publisher} resembles an ordinary {@code Publisher}, except that it does not begin emitting items when it is + * that will replay all of its items and notifications to any future {@link Subscriber}. A connectable + * {@code Flowable} resembles an ordinary {@code Flowable}, except that it does not begin emitting items when it is * subscribed to, but only when its {@code connect} method is called. *

- * + * *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child * {@code Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * request 100 elements from the current {@code Flowable} sequence.
*
Scheduler:
*
This version of {@code replay} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code ConnectableFlowable} that upon connection causes the source {@code Publisher} to emit its - * items to its {@code Subscriber}s + * @return the new {@code ConnectableFlowable} instance * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @@ -12894,64 +13768,64 @@ public final ConnectableFlowable replay() { /** * Returns a {@code Flowable} that emits items that are the results of invoking a specified selector on the items - * emitted by a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher}. + * emitted by a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable}. *

- * + * *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * request 100 elements from the current {@code Flowable} sequence.
*
Scheduler:
*
This version of {@code replay} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param selector * the selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the {@code Publisher} - * @return a {@code Flowable} that emits items that are the results of invoking the selector on a - * {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher} + * causing multiple subscriptions to the current {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code selector} is {@code null} * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable replay(@NonNull Function, ? extends Publisher> selector) { + public final <@NonNull R> Flowable replay(@NonNull Function, @NonNull ? extends Publisher> selector) { Objects.requireNonNull(selector, "selector is null"); return FlowableReplay.multicastSelector(FlowableInternalHelper.replaySupplier(this), selector); } /** * Returns a {@code Flowable} that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher}, + * emitted by a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable}, * replaying {@code bufferSize} notifications. *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. *

- * + * *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * request 100 elements from the current {@code Flowable} sequence.
*
Scheduler:
*
This version of {@code replay} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param selector * the selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the {@code Publisher} + * causing multiple subscriptions to the current {@code Flowable} * @param bufferSize - * the buffer size that limits the number of items the connectable {@code Publisher} can replay - * @return a {@code Flowable} that emits items that are the results of invoking the selector on items emitted by - * a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher} - * replaying no more than {@code bufferSize} items + * the buffer size that limits the number of items the operator can replay + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code selector} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay * @see #replay(Function, int, boolean) */ @@ -12959,7 +13833,7 @@ public final Flowable replay(@NonNull Function, ? ext @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable replay(@NonNull Function, ? extends Publisher> selector, int bufferSize) { + public final <@NonNull R> Flowable replay(@NonNull Function, @NonNull ? extends Publisher> selector, int bufferSize) { Objects.requireNonNull(selector, "selector is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); return FlowableReplay.multicastSelector(FlowableInternalHelper.replaySupplier(this, bufferSize, false), selector); @@ -12967,42 +13841,42 @@ public final Flowable replay(@NonNull Function, ? ext /** * Returns a {@code Flowable} that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher}, + * emitted by a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable}, * replaying {@code bufferSize} notifications. *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. *

- * + * *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
This version of {@code replay} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param selector * the selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the {@code Publisher} + * causing multiple subscriptions to the current {@code Flowable} * @param bufferSize - * the buffer size that limits the number of items the connectable {@code Publisher} can replay + * the buffer size that limits the number of items the operator can replay * @param eagerTruncate * if {@code true}, whenever the internal buffer is truncated to the given bufferSize, the * oldest item will be guaranteed dereferenced, thus avoiding unexpected retention - * @return a {@code Flowable} that emits items that are the results of invoking the selector on items emitted by - * a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher} - * replaying no more than {@code bufferSize} items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code selector} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable replay(@NonNull Function, ? extends Publisher> selector, int bufferSize, boolean eagerTruncate) { + public final <@NonNull R> Flowable replay(@NonNull Function, @NonNull ? extends Publisher> selector, int bufferSize, boolean eagerTruncate) { Objects.requireNonNull(selector, "selector is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); return FlowableReplay.multicastSelector(FlowableInternalHelper.replaySupplier(this, bufferSize, eagerTruncate), selector); @@ -13010,84 +13884,81 @@ public final Flowable replay(@NonNull Function, ? ext /** * Returns a {@code Flowable} that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher}, + * emitted by a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable}, * replaying no more than {@code bufferSize} items that were emitted within a specified time window. *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. *

- * + * *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
This version of {@code replay} operates by default on the {@code computation} {@link Scheduler}.
*
* * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param selector * a selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the {@code Publisher} + * causing multiple subscriptions to the current {@code Flowable} * @param bufferSize - * the buffer size that limits the number of items the connectable {@code Publisher} can replay + * the buffer size that limits the number of items the operator can replay * @param time * the duration of the window in which the replayed items must have been emitted * @param unit * the time unit of {@code time} - * @return a {@code Flowable} that emits items that are the results of invoking the selector on items emitted by - * a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher}, and - * replays no more than {@code bufferSize} items that were emitted within the window defined by - * {@code time} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code selector} or {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Flowable replay(@NonNull Function, ? extends Publisher> selector, int bufferSize, long time, @NonNull TimeUnit unit) { + public final <@NonNull R> Flowable replay(@NonNull Function, @NonNull ? extends Publisher> selector, int bufferSize, long time, @NonNull TimeUnit unit) { return replay(selector, bufferSize, time, unit, Schedulers.computation()); } /** * Returns a {@code Flowable} that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher}, + * emitted by a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable}, * replaying no more than {@code bufferSize} items that were emitted within a specified time window. *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. *

- * + * *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
* * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param selector * a selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the {@code Publisher} + * causing multiple subscriptions to the current {@code Flowable} * @param bufferSize - * the buffer size that limits the number of items the connectable {@code Publisher} can replay + * the buffer size that limits the number of items the operator can replay * @param time * the duration of the window in which the replayed items must have been emitted * @param unit * the time unit of {@code time} * @param scheduler * the {@code Scheduler} that is the time source for the window - * @return a {@code Flowable} that emits items that are the results of invoking the selector on items emitted by - * a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher}, and - * replays no more than {@code bufferSize} items that were emitted within the window defined by - * {@code time} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code selector}, {@code unit} or {@code scheduler} is {@code null} * @throws IllegalArgumentException - * if {@code bufferSize} is less than zero + * if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay * @see #replay(Function, int, long, TimeUnit, Scheduler, boolean) */ @@ -13095,7 +13966,7 @@ public final Flowable replay(@NonNull Function, ? ext @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Flowable replay(@NonNull Function, ? extends Publisher> selector, int bufferSize, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + public final <@NonNull R> Flowable replay(@NonNull Function, @NonNull ? extends Publisher> selector, int bufferSize, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { Objects.requireNonNull(selector, "selector is null"); Objects.requireNonNull(unit, "unit is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); @@ -13106,29 +13977,29 @@ public final Flowable replay(@NonNull Function, ? ext /** * Returns a {@code Flowable} that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher}, + * emitted by a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable}, * replaying no more than {@code bufferSize} items that were emitted within a specified time window. *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. *

- * + * *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
* * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param selector * a selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the {@code Publisher} + * causing multiple subscriptions to the current {@code Flowable} * @param bufferSize - * the buffer size that limits the number of items the connectable {@code Publisher} can replay + * the buffer size that limits the number of items the operator can replay * @param time * the duration of the window in which the replayed items must have been emitted * @param unit @@ -13138,10 +14009,8 @@ public final Flowable replay(@NonNull Function, ? ext * @param eagerTruncate * if {@code true}, whenever the internal buffer is truncated to the given bufferSize/age, the * oldest item will be guaranteed dereferenced, thus avoiding unexpected retention - * @return a {@code Flowable} that emits items that are the results of invoking the selector on items emitted by - * a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher}, and - * replays no more than {@code bufferSize} items that were emitted within the window defined by - * {@code time} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code selector}, {@code unit} or {@code scheduler} is {@code null} * @throws IllegalArgumentException * if {@code bufferSize} is less than zero * @see ReactiveX operators documentation: Replay @@ -13150,7 +14019,7 @@ public final Flowable replay(@NonNull Function, ? ext @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Flowable replay(@NonNull Function, ? extends Publisher> selector, int bufferSize, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean eagerTruncate) { + public final <@NonNull R> Flowable replay(@NonNull Function, @NonNull ? extends Publisher> selector, int bufferSize, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean eagerTruncate) { Objects.requireNonNull(selector, "selector is null"); Objects.requireNonNull(unit, "unit is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); @@ -13161,70 +14030,68 @@ public final Flowable replay(@NonNull Function, ? ext /** * Returns a {@code Flowable} that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher}, + * emitted by a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable}, * replaying all items that were emitted within a specified time window. *

- * + * *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
This version of {@code replay} operates by default on the {@code computation} {@link Scheduler}.
*
* * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param selector * a selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the {@code Publisher} + * causing multiple subscriptions to the current {@code Flowable} * @param time * the duration of the window in which the replayed items must have been emitted * @param unit * the time unit of {@code time} - * @return a {@code Flowable} that emits items that are the results of invoking the selector on items emitted by - * a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher}, - * replaying all items that were emitted within the window defined by {@code time} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code selector} or {@code unit} is {@code null} * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Flowable replay(@NonNull Function, ? extends Publisher> selector, long time, @NonNull TimeUnit unit) { + public final <@NonNull R> Flowable replay(@NonNull Function, @NonNull ? extends Publisher> selector, long time, @NonNull TimeUnit unit) { return replay(selector, time, unit, Schedulers.computation()); } /** * Returns a {@code Flowable} that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher}, + * emitted by a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable}, * replaying all items that were emitted within a specified time window. *

- * + * *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
* * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param selector * a selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the {@code Publisher} + * causing multiple subscriptions to the current {@code Flowable} * @param time * the duration of the window in which the replayed items must have been emitted * @param unit * the time unit of {@code time} * @param scheduler * the scheduler that is the time source for the window - * @return a {@code Flowable} that emits items that are the results of invoking the selector on items emitted by - * a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher}, - * replaying all items that were emitted within the window defined by {@code time} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code selector}, {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Replay * @see #replay(Function, long, TimeUnit, Scheduler, boolean) */ @@ -13232,7 +14099,7 @@ public final Flowable replay(@NonNull Function, ? ext @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Flowable replay(@NonNull Function, ? extends Publisher> selector, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + public final <@NonNull R> Flowable replay(@NonNull Function, @NonNull ? extends Publisher> selector, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { Objects.requireNonNull(selector, "selector is null"); Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); @@ -13241,24 +14108,24 @@ public final Flowable replay(@NonNull Function, ? ext /** * Returns a {@code Flowable} that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher}, + * emitted by a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable}, * replaying all items that were emitted within a specified time window. *

- * + * *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
* * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param selector * a selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the {@code Publisher} + * causing multiple subscriptions to the current {@code Flowable} * @param time * the duration of the window in which the replayed items must have been emitted * @param unit @@ -13268,16 +14135,15 @@ public final Flowable replay(@NonNull Function, ? ext * @param eagerTruncate * if {@code true}, whenever the internal buffer is truncated to the given age, the * oldest item will be guaranteed dereferenced, thus avoiding unexpected retention - * @return a {@code Flowable} that emits items that are the results of invoking the selector on items emitted by - * a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher}, - * replaying all items that were emitted within the window defined by {@code time} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code selector}, {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Flowable replay(@NonNull Function, ? extends Publisher> selector, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean eagerTruncate) { + public final <@NonNull R> Flowable replay(@NonNull Function, @NonNull ? extends Publisher> selector, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean eagerTruncate) { Objects.requireNonNull(selector, "selector is null"); Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); @@ -13285,9 +14151,9 @@ public final Flowable replay(@NonNull Function, ? ext } /** - * Returns a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher} that - * replays at most {@code bufferSize} items emitted by that {@code Publisher}. A Connectable {@code Publisher} resembles - * an ordinary {@code Publisher}, except that it does not begin emitting items when it is subscribed to, but only + * Returns a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable} and + * replays at most {@code bufferSize} items to late {@link Subscriber}s. A Connectable {@code Flowable} resembles + * an ordinary {@code Flowable}, except that it does not begin emitting items when it is subscribed to, but only * when its {@code connect} method is called. *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than @@ -13295,20 +14161,20 @@ public final Flowable replay(@NonNull Function, ? ext * To ensure no beyond-bufferSize items are referenced, * use the {@link #replay(int, boolean)} overload with {@code eagerTruncate = true}. *

- * + * *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child - * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * {@code Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will + * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
This version of {@code replay} does not operate by default on a particular {@link Scheduler}.
*
* * @param bufferSize * the buffer size that limits the number of items that can be replayed - * @return a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher} and - * replays at most {@code bufferSize} items emitted by that {@code Publisher} + * @return the new {@code ConnectableFlowable} instance + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay * @see #replay(int, boolean) */ @@ -13321,12 +14187,12 @@ public final ConnectableFlowable replay(int bufferSize) { return FlowableReplay.create(this, bufferSize, false); } /** - * Returns a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher} that - * replays at most {@code bufferSize} items emitted by that {@code Publisher}. A Connectable {@code Publisher} resembles - * an ordinary {@code Publisher}, except that it does not begin emitting items when it is subscribed to, but only + * Returns a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable} and + * replays at most {@code bufferSize} items to late {@link Subscriber}s. A connectable {@code Flowable} resembles + * an ordinary {@code Flowable}, except that it does not begin emitting items when it is subscribed to, but only * when its {@code connect} method is called. *

- * + * *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. @@ -13334,8 +14200,8 @@ public final ConnectableFlowable replay(int bufferSize) { *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child - * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * {@code Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will + * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
This version of {@code replay} does not operate by default on a particular {@link Scheduler}.
*
@@ -13345,8 +14211,8 @@ public final ConnectableFlowable replay(int bufferSize) { * @param eagerTruncate * if {@code true}, whenever the internal buffer is truncated to the given bufferSize, the * oldest item will be guaranteed dereferenced, thus avoiding unexpected retention - * @return a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher} and - * replays at most {@code bufferSize} items emitted by that {@code Publisher} + * @return the new {@code ConnectableFlowable} instance + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay * @since 3.0.0 */ @@ -13360,12 +14226,12 @@ public final ConnectableFlowable replay(int bufferSize, boolean eagerTruncate } /** - * Returns a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher} and - * replays at most {@code bufferSize} items that were emitted during a specified time window. A Connectable - * {@code Publisher} resembles an ordinary {@code Publisher}, except that it does not begin emitting items when it is + * Returns a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable} and + * replays at most {@code bufferSize} items that were emitted during a specified time window. A connectable + * {@code Flowable} resembles an ordinary {@code Flowable}, except that it does not begin emitting items when it is * subscribed to, but only when its {@code connect} method is called. *

- * + * *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. @@ -13375,7 +14241,7 @@ public final ConnectableFlowable replay(int bufferSize, boolean eagerTruncate *

Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
This version of {@code replay} operates by default on the {@code computation} {@link Scheduler}.
* @@ -13386,9 +14252,9 @@ public final ConnectableFlowable replay(int bufferSize, boolean eagerTruncate * the duration of the window in which the replayed items must have been emitted * @param unit * the time unit of {@code time} - * @return a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher} and - * replays at most {@code bufferSize} items that were emitted during the window defined by - * {@code time} + * @return the new {@code ConnectableFlowable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay * @see #replay(int, long, TimeUnit, Scheduler, boolean) */ @@ -13401,12 +14267,12 @@ public final ConnectableFlowable replay(int bufferSize, long time, @NonNull T } /** - * Returns a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher} and - * that replays a maximum of {@code bufferSize} items that are emitted within a specified time window. A - * Connectable {@code Publisher} resembles an ordinary {@code Publisher}, except that it does not begin emitting items + * Returns a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable} and + * replays a maximum of {@code bufferSize} items that are emitted within a specified time window to late {@link Subscriber}s. A + * connectable {@code Flowable} resembles an ordinary {@code Flowable}, except that it does not begin emitting items * when it is subscribed to, but only when its {@code connect} method is called. *

- * + * *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. @@ -13415,8 +14281,8 @@ public final ConnectableFlowable replay(int bufferSize, long time, @NonNull T *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child - * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * {@code Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will + * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
@@ -13429,11 +14295,9 @@ public final ConnectableFlowable replay(int bufferSize, long time, @NonNull T * the time unit of {@code time} * @param scheduler * the scheduler that is used as a time source for the window - * @return a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher} and - * replays at most {@code bufferSize} items that were emitted during the window defined by - * {@code time} - * @throws IllegalArgumentException - * if {@code bufferSize} is less than zero + * @return the new {@code ConnectableFlowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay * @see #replay(int, long, TimeUnit, Scheduler, boolean) */ @@ -13442,7 +14306,6 @@ public final ConnectableFlowable replay(int bufferSize, long time, @NonNull T @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull public final ConnectableFlowable replay(int bufferSize, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); @@ -13450,21 +14313,21 @@ public final ConnectableFlowable replay(int bufferSize, long time, @NonNull T } /** - * Returns a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher} and - * that replays a maximum of {@code bufferSize} items that are emitted within a specified time window. A - * Connectable {@code Publisher} resembles an ordinary {@code Publisher}, except that it does not begin emitting items + * Returns a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable} and + * replays a maximum of {@code bufferSize} items that are emitted within a specified time window to late {@link Subscriber}s. A + * connectable {@code Flowable} resembles an ordinary {@code Flowable}, except that it does not begin emitting items * when it is subscribed to, but only when its {@code connect} method is called. *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. To ensure no out-of-date or beyond-bufferSize items * are referenced, set {@code eagerTruncate = true}. *

- * + * *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child - * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * {@code Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will + * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
@@ -13480,11 +14343,9 @@ public final ConnectableFlowable replay(int bufferSize, long time, @NonNull T * @param eagerTruncate * if {@code true}, whenever the internal buffer is truncated to the given bufferSize/age, the * oldest item will be guaranteed dereferenced, thus avoiding unexpected retention - * @return a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher} and - * replays at most {@code bufferSize} items that were emitted during the window defined by - * {@code time} - * @throws IllegalArgumentException - * if {@code bufferSize} is less than zero + * @return the new {@code ConnectableFlowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay * @since 3.0.0 */ @@ -13493,7 +14354,6 @@ public final ConnectableFlowable replay(int bufferSize, long time, @NonNull T @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull public final ConnectableFlowable replay(int bufferSize, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean eagerTruncate) { - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); @@ -13501,20 +14361,20 @@ public final ConnectableFlowable replay(int bufferSize, long time, @NonNull T } /** - * Returns a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher} and - * replays all items emitted by that {@code Publisher} within a specified time window. A Connectable {@code Publisher} - * resembles an ordinary {@code Publisher}, except that it does not begin emitting items when it is subscribed to, + * Returns a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable} and + * replays all items emitted by it within a specified time window to late {@link Subscriber}s. A connectable {@code Flowable} + * resembles an ordinary {@code Flowable}, except that it does not begin emitting items when it is subscribed to, * but only when its {@code connect} method is called. *

- * + * *

* Note that the internal buffer may retain strong references to the oldest item. To ensure no out-of-date items * are referenced, use the {@link #replay(long, TimeUnit, Scheduler, boolean)} overload with {@code eagerTruncate = true}. *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child - * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * {@code Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will + * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
This version of {@code replay} operates by default on the {@code computation} {@link Scheduler}.
*
@@ -13523,8 +14383,8 @@ public final ConnectableFlowable replay(int bufferSize, long time, @NonNull T * the duration of the window in which the replayed items must have been emitted * @param unit * the time unit of {@code time} - * @return a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher} and - * replays the items that were emitted during the window defined by {@code time} + * @return the new {@code ConnectableFlowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @@ -13536,20 +14396,20 @@ public final ConnectableFlowable replay(long time, @NonNull TimeUnit unit) { } /** - * Returns a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher} and - * replays all items emitted by that {@code Publisher} within a specified time window. A Connectable {@code Publisher} - * resembles an ordinary {@code Publisher}, except that it does not begin emitting items when it is subscribed to, + * Returns a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable} and + * replays all items emitted by it within a specified time window to late {@link Subscriber}s. A connectable {@code Flowable} + * resembles an ordinary {@code Flowable}, except that it does not begin emitting items when it is subscribed to, * but only when its {@code connect} method is called. *

- * + * *

* Note that the internal buffer may retain strong references to the oldest item. To ensure no out-of-date items * are referenced, use the {@link #replay(long, TimeUnit, Scheduler, boolean)} overload with {@code eagerTruncate = true}. *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child - * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * {@code Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will + * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
@@ -13560,8 +14420,8 @@ public final ConnectableFlowable replay(long time, @NonNull TimeUnit unit) { * the time unit of {@code time} * @param scheduler * the {@code Scheduler} that is the time source for the window - * @return a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher} and - * replays the items that were emitted during the window defined by {@code time} + * @return the new {@code ConnectableFlowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Replay * @see #replay(long, TimeUnit, Scheduler, boolean) */ @@ -13576,20 +14436,20 @@ public final ConnectableFlowable replay(long time, @NonNull TimeUnit unit, @N } /** - * Returns a {@link ConnectableFlowable} that shares a single subscription to the source {@link Publisher} and - * replays all items emitted by that {@code Publisher} within a specified time window. A Connectable {@code Publisher} - * resembles an ordinary {@code Publisher}, except that it does not begin emitting items when it is subscribed to, + * Returns a {@link ConnectableFlowable} that shares a single subscription to the current {@code Flowable} and + * replays all items emitted by it within a specified time window to late {@link Subscriber}s. A connectable {@code Flowable} + * resembles an ordinary {@code Flowable}, except that it does not begin emitting items when it is subscribed to, * but only when its {@code connect} method is called. *

- * + * *

* Note that the internal buffer may retain strong references to the oldest item. To ensure no out-of-date items * are referenced, set {@code eagerTruncate = true}. *

*
Backpressure:
*
This operator supports backpressure. Note that the upstream requests are determined by the child - * {@link Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will - * request 100 elements from the underlying {@code Publisher} sequence.
+ * {@code Subscriber} which requests the largest amount: i.e., two child {@code Subscriber}s with requests of 10 and 100 will + * request 100 elements from the current {@code Flowable} sequence. *
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
@@ -13603,8 +14463,8 @@ public final ConnectableFlowable replay(long time, @NonNull TimeUnit unit, @N * @param eagerTruncate * if {@code true}, whenever the internal buffer is truncated to the given bufferSize/age, the * oldest item will be guaranteed dereferenced, thus avoiding unexpected retention - * @return a {@code ConnectableFlowable} that shares a single subscription to the source {@code Publisher} and - * replays the items that were emitted during the window defined by {@code time} + * @return the new {@code ConnectableFlowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @@ -13618,27 +14478,27 @@ public final ConnectableFlowable replay(long time, @NonNull TimeUnit unit, @N } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher}, resubscribing to it if it calls {@code onError} + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, resubscribing to it if it calls {@code onError} * (infinite retry count). *

- * + * *

- * If the source {@code Publisher} calls {@link Subscriber#onError}, this method will resubscribe to the source - * {@code Publisher} rather than propagating the {@code onError} call. + * If the current {@code Flowable} calls {@link Subscriber#onError}, this method will resubscribe to the current + * {@code Flowable} rather than propagating the {@code onError} call. *

- * Any and all items emitted by the source {@code Publisher} will be emitted by the resulting {@code Publisher}, even - * those emitted during failed subscriptions. For example, if a {@code Publisher} fails at first but emits + * Any and all items emitted by the current {@code Flowable} will be emitted by the resulting {@code Flowable}, even + * those emitted during failed subscriptions. For example, if the current {@code Flowable} fails at first but emits * {@code [1, 2]} then succeeds the second time and emits {@code [1, 2, 3, 4, 5]} then the complete sequence * of emissions and notifications would be {@code [1, 2, 1, 2, 3, 4, 5, onComplete]}. *

*
Backpressure:
- *
The operator honors downstream backpressure and expects the source {@code Publisher} to honor backpressure as well. + *
The operator honors downstream backpressure and expects the current {@code Flowable} to honor backpressure as well. * If this expectation is violated, the operator may throw an {@link IllegalStateException}.
*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
* - * @return the source {@code Publisher} modified with retry logic + * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: Retry */ @CheckReturnValue @@ -13650,13 +14510,13 @@ public final Flowable retry() { } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher}, resubscribing to it if it calls {@code onError} + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, resubscribing to it if it calls {@code onError} * and the predicate returns {@code true} for that specific exception and retry count. *

- * + * *

*
Backpressure:
- *
The operator honors downstream backpressure and expects the source {@code Publisher} to honor backpressure as well. + *
The operator honors downstream backpressure and expects the current {@code Flowable} to honor backpressure as well. * If this expectation is violated, the operator may throw an {@link IllegalStateException}.
*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
@@ -13665,7 +14525,8 @@ public final Flowable retry() { * @param predicate * the predicate that determines if a resubscription may happen in case of a specific exception * and retry count - * @return the source {@code Publisher} modified with retry logic + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @see #retry() * @see ReactiveX operators documentation: Retry */ @@ -13680,38 +14541,39 @@ public final Flowable retry(@NonNull BiPredicate<@NonNull ? super Integer, @N } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher}, resubscribing to it if it calls {@code onError} + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, resubscribing to it if it calls {@code onError} * up to a specified number of retries. *

- * + * *

- * If the source {@code Publisher} calls {@link Subscriber#onError}, this method will resubscribe to the source - * {@code Publisher} for a maximum of {@code count} resubscriptions rather than propagating the + * If the current {@code Flowable} calls {@link Subscriber#onError}, this method will resubscribe to the current + * {@code Flowable} for a maximum of {@code count} resubscriptions rather than propagating the * {@code onError} call. *

- * Any and all items emitted by the source {@code Publisher} will be emitted by the resulting {@code Publisher}, even - * those emitted during failed subscriptions. For example, if a {@code Publisher} fails at first but emits + * Any and all items emitted by the current {@code Flowable} will be emitted by the resulting {@code Flowable}, even + * those emitted during failed subscriptions. For example, if the current {@code Flowable} fails at first but emits * {@code [1, 2]} then succeeds the second time and emits {@code [1, 2, 3, 4, 5]} then the complete sequence * of emissions and notifications would be {@code [1, 2, 1, 2, 3, 4, 5, onComplete]}. *

*
Backpressure:
- *
The operator honors downstream backpressure and expects the source {@code Publisher} to honor backpressure as well. + *
The operator honors downstream backpressure and expects the current {@code Flowable} to honor backpressure as well. * If this expectation is violated, the operator may throw an {@link IllegalStateException}.
*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
* - * @param count + * @param times * the number of times to resubscribe if the current {@code Flowable} fails - * @return the source {@code Publisher} modified with retry logic + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code times} is negative * @see ReactiveX operators documentation: Retry */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable retry(long count) { - return retry(count, Functions.alwaysTrue()); + public final Flowable retry(long times) { + return retry(times, Functions.alwaysTrue()); } /** @@ -13719,13 +14581,15 @@ public final Flowable retry(long count) { * *
*
Backpressure:
- *
The operator honors downstream backpressure and expects the source {@link Publisher} to honor backpressure as well. + *
The operator honors downstream backpressure and expects the current {@code Flowable} to honor backpressure as well. * If this expectation is violated, the operator may throw an {@link IllegalStateException}.
*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
* @param times the number of times to resubscribe if the current {@code Flowable} fails * @param predicate the predicate called with the failure {@link Throwable} and should return {@code true} to trigger a retry. + * @throws NullPointerException if {@code predicate} is {@code null} + * @throws IllegalArgumentException if {@code times} is negative * @return the new {@code Flowable} instance */ @CheckReturnValue @@ -13745,7 +14609,7 @@ public final Flowable retry(long times, @NonNull Predicate<@NonNull ? super T * Retries the current {@code Flowable} if the predicate returns {@code true}. *
*
Backpressure:
- *
The operator honors downstream backpressure and expects the source {@link Publisher} to honor backpressure as well. + *
The operator honors downstream backpressure and expects the current {@code Flowable} to honor backpressure as well. * If this expectation is violated, the operator may throw an {@link IllegalStateException}.
*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
@@ -13753,6 +14617,7 @@ public final Flowable retry(long times, @NonNull Predicate<@NonNull ? super T * * @param predicate the predicate that receives the failure {@link Throwable} and should return {@code true} to trigger a retry. * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code predicate} is {@code null} */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @@ -13766,13 +14631,14 @@ public final Flowable retry(@NonNull Predicate<@NonNull ? super Throwable> pr * Retries until the given stop function returns {@code true}. *
*
Backpressure:
- *
The operator honors downstream backpressure and expects the source {@link Publisher} to honor backpressure as well. + *
The operator honors downstream backpressure and expects the current {@code Flowable} to honor backpressure as well. * If this expectation is violated, the operator may throw an {@link IllegalStateException}.
*
Scheduler:
*
{@code retryUntil} does not operate by default on a particular {@link Scheduler}.
*
* @param stop the function that should return {@code true} to stop retrying * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code stop} is {@code null} */ @CheckReturnValue @NonNull @@ -13784,14 +14650,14 @@ public final Flowable retryUntil(@NonNull BooleanSupplier stop) { } /** - * Returns a {@code Flowable} that emits the same values as the source {@link Publisher} with the exception of an + * Returns a {@code Flowable} that emits the same values as the current {@code Flowable} with the exception of an * {@code onError}. An {@code onError} notification from the source will result in the emission of a - * {@link Throwable} item to the {@code Publisher} provided as an argument to the {@code notificationHandler} - * function. If that {@code Publisher} calls {@code onComplete} or {@code onError} then {@code retry} will call + * {@link Throwable} item to the {@code Flowable} provided as an argument to the {@code notificationHandler} + * function. If that {@link Publisher} calls {@code onComplete} or {@code onError} then {@code retry} will call * {@code onComplete} or {@code onError} on the child subscription. Otherwise, this {@code Publisher} will - * resubscribe to the source {@code Publisher}. + * resubscribe to the current {@code Flowable}. *

- * + * *

* Example: * @@ -13857,7 +14723,8 @@ public final Flowable retryUntil(@NonNull BooleanSupplier stop) { * @param handler * receives a {@code Publisher} of notifications with which a user can complete or error, aborting the * retry - * @return the source {@code Publisher} modified with retry logic + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code handler} is {@code null} * @see ReactiveX operators documentation: Retry */ @CheckReturnValue @@ -13865,7 +14732,7 @@ public final Flowable retryUntil(@NonNull BooleanSupplier stop) { @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) public final Flowable retryWhen( - @NonNull Function, ? extends Publisher> handler) { + @NonNull Function, @NonNull ? extends Publisher<@NonNull ?>> handler) { Objects.requireNonNull(handler, "handler is null"); return RxJavaPlugins.onAssembly(new FlowableRetryWhen<>(this, handler)); @@ -13882,25 +14749,25 @@ public final Flowable retryWhen( *

Scheduler:
*
{@code safeSubscribe} does not operate by default on a particular {@link Scheduler}.
*
- * @param s the incoming {@code Subscriber} instance - * @throws NullPointerException if s is {@code null} + * @param subscriber the incoming {@code Subscriber} instance + * @throws NullPointerException if {@code subscriber} is {@code null} */ @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public final void safeSubscribe(@NonNull Subscriber s) { - Objects.requireNonNull(s, "s is null"); - if (s instanceof SafeSubscriber) { - subscribe((SafeSubscriber)s); + public final void safeSubscribe(@NonNull Subscriber subscriber) { + Objects.requireNonNull(subscriber, "subscriber is null"); + if (subscriber instanceof SafeSubscriber) { + subscribe((SafeSubscriber)subscriber); } else { - subscribe(new SafeSubscriber<>(s)); + subscribe(new SafeSubscriber<>(subscriber)); } } /** - * Returns a {@code Flowable} that emits the most recently emitted item (if any) emitted by the source {@link Publisher} + * Returns a {@code Flowable} that emits the most recently emitted item (if any) emitted by the current {@code Flowable} * within periodic time intervals. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time to control data flow.
@@ -13912,8 +14779,8 @@ public final void safeSubscribe(@NonNull Subscriber s) { * the sampling rate * @param unit * the {@link TimeUnit} in which {@code period} is defined - * @return a {@code Flowable} that emits the results of sampling the items emitted by the source {@code Publisher} at - * the specified time interval + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Sample * @see RxJava wiki: Backpressure * @see #throttleLast(long, TimeUnit) @@ -13927,10 +14794,10 @@ public final Flowable sample(long period, @NonNull TimeUnit unit) { } /** - * Returns a {@code Flowable} that emits the most recently emitted item (if any) emitted by the source {@link Publisher} + * Returns a {@code Flowable} that emits the most recently emitted item (if any) emitted by the current {@code Flowable} * within periodic time intervals and optionally emit the very last upstream item when the upstream completes. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time to control data flow.
@@ -13947,8 +14814,8 @@ public final Flowable sample(long period, @NonNull TimeUnit unit) { * if {@code true}, and the upstream completes while there is still an unsampled item available, * that item is emitted to downstream before completion * if {@code false}, an unsampled last item is ignored. - * @return a {@code Flowable} that emits the results of sampling the items emitted by the source {@code Publisher} at - * the specified time interval + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Sample * @see RxJava wiki: Backpressure * @see #throttleLast(long, TimeUnit) @@ -13963,10 +14830,10 @@ public final Flowable sample(long period, @NonNull TimeUnit unit, boolean emi } /** - * Returns a {@code Flowable} that emits the most recently emitted item (if any) emitted by the source {@link Publisher} + * Returns a {@code Flowable} that emits the most recently emitted item (if any) emitted by the current {@code Flowable} * within periodic time intervals, where the intervals are defined on a particular {@link Scheduler}. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time to control data flow.
@@ -13980,8 +14847,8 @@ public final Flowable sample(long period, @NonNull TimeUnit unit, boolean emi * the {@link TimeUnit} in which {@code period} is defined * @param scheduler * the {@code Scheduler} to use when sampling - * @return a {@code Flowable} that emits the results of sampling the items emitted by the source {@code Publisher} at - * the specified time interval + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Sample * @see RxJava wiki: Backpressure * @see #throttleLast(long, TimeUnit, Scheduler) @@ -13993,15 +14860,15 @@ public final Flowable sample(long period, @NonNull TimeUnit unit, boolean emi public final Flowable sample(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new FlowableSampleTimed<>(this, period, unit, scheduler, false)); + return RxJavaPlugins.onAssembly(new FlowableSampleTimed<>(this, period, unit, scheduler, false, null)); } /** - * Returns a {@code Flowable} that emits the most recently emitted item (if any) emitted by the source {@link Publisher} + * Returns a {@code Flowable} that emits the most recently emitted item (if any) emitted by the current {@code Flowable} * within periodic time intervals, where the intervals are defined on a particular {@link Scheduler} * and optionally emit the very last upstream item when the upstream completes. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time to control data flow.
@@ -14020,8 +14887,8 @@ public final Flowable sample(long period, @NonNull TimeUnit unit, @NonNull Sc * if {@code true} and the upstream completes while there is still an unsampled item available, * that item is emitted to downstream before completion * if {@code false}, an unsampled last item is ignored. - * @return a {@code Flowable} that emits the results of sampling the items emitted by the source {@code Publisher} at - * the specified time interval + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Sample * @see RxJava wiki: Backpressure * @see #throttleLast(long, TimeUnit, Scheduler) @@ -14034,15 +14901,59 @@ public final Flowable sample(long period, @NonNull TimeUnit unit, @NonNull Sc public final Flowable sample(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new FlowableSampleTimed<>(this, period, unit, scheduler, emitLast)); + return RxJavaPlugins.onAssembly(new FlowableSampleTimed<>(this, period, unit, scheduler, emitLast, null)); + } + + /** + * Returns a {@code Flowable} that emits the most recently emitted item (if any) emitted by the current {@code Flowable} + * within periodic time intervals, where the intervals are defined on a particular {@link Scheduler} + * and optionally emit the very last upstream item when the upstream completes. + *

+ * + *

+ *
Backpressure:
+ *
This operator does not support backpressure as it uses time to control data flow.
+ *
Scheduler:
+ *
You specify which {@code Scheduler} this operator will use.
+ *
+ * + * @param period + * the sampling rate + * @param unit + * the {@link TimeUnit} in which {@code period} is defined + * @param scheduler + * the {@code Scheduler} to use when sampling + * @param emitLast + * if {@code true} and the upstream completes while there is still an unsampled item available, + * that item is emitted to downstream before completion + * if {@code false}, an unsampled last item is ignored. + * @param onDropped + * called with the current entry when it has been replaced by a new one + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} or {@code onDropped} is {@code null} + * @see ReactiveX operators documentation: Sample + * @see RxJava wiki: Backpressure + * @see #throttleLast(long, TimeUnit, Scheduler) + * @since 3.1.6 - Experimental + */ + @CheckReturnValue + @NonNull + @BackpressureSupport(BackpressureKind.ERROR) + @SchedulerSupport(SchedulerSupport.CUSTOM) + @Experimental + public final Flowable sample(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast, @NonNull Consumer onDropped) { + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + Objects.requireNonNull(onDropped, "onDropped is null"); + return RxJavaPlugins.onAssembly(new FlowableSampleTimed<>(this, period, unit, scheduler, emitLast, onDropped)); } /** * Returns a {@code Flowable} that, when the specified {@code sampler} {@link Publisher} emits an item or completes, - * emits the most recently emitted item (if any) emitted by the source {@code Publisher} since the previous + * emits the most recently emitted item (if any) emitted by the current {@code Flowable} since the previous * emission from the {@code sampler} {@code Publisher}. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses the emissions of the {@code sampler} @@ -14053,9 +14964,9 @@ public final Flowable sample(long period, @NonNull TimeUnit unit, @NonNull Sc * * @param the element type of the sampler {@code Publisher} * @param sampler - * the {@code Publisher} to use for sampling the source {@code Publisher} - * @return a {@code Flowable} that emits the results of sampling the items emitted by this {@code Publisher} whenever - * the {@code sampler} {@code Publisher} emits an item or completes + * the {@code Publisher} to use for sampling the current {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sampler} is {@code null} * @see ReactiveX operators documentation: Sample * @see RxJava wiki: Backpressure */ @@ -14063,18 +14974,18 @@ public final Flowable sample(long period, @NonNull TimeUnit unit, @NonNull Sc @NonNull @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable sample(@NonNull Publisher sampler) { + public final <@NonNull U> Flowable sample(@NonNull Publisher sampler) { Objects.requireNonNull(sampler, "sampler is null"); return RxJavaPlugins.onAssembly(new FlowableSamplePublisher<>(this, sampler, false)); } /** * Returns a {@code Flowable} that, when the specified {@code sampler} {@link Publisher} emits an item or completes, - * emits the most recently emitted item (if any) emitted by the source {@code Publisher} since the previous + * emits the most recently emitted item (if any) emitted by the current {@code Flowable} since the previous * emission from the {@code sampler} {@code Publisher} * and optionally emit the very last upstream item when the upstream or other {@code Publisher} complete. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses the emissions of the {@code sampler} @@ -14086,13 +14997,13 @@ public final Flowable sample(@NonNull Publisher sampler) { *

History: 2.0.5 - experimental * @param the element type of the sampler {@code Publisher} * @param sampler - * the {@code Publisher} to use for sampling the source {@code Publisher} + * the {@code Publisher} to use for sampling the current {@code Flowable} * @param emitLast * if {@code true} and the upstream completes while there is still an unsampled item available, * that item is emitted to downstream before completion * if {@code false}, an unsampled last item is ignored. - * @return a {@code Flowable} that emits the results of sampling the items emitted by this {@code Publisher} whenever - * the {@code sampler} {@code Publisher} emits an item or completes + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sampler} is {@code null} * @see ReactiveX operators documentation: Sample * @see RxJava wiki: Backpressure * @since 2.1 @@ -14101,33 +15012,33 @@ public final Flowable sample(@NonNull Publisher sampler) { @NonNull @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable sample(@NonNull Publisher sampler, boolean emitLast) { + public final <@NonNull U> Flowable sample(@NonNull Publisher sampler, boolean emitLast) { Objects.requireNonNull(sampler, "sampler is null"); return RxJavaPlugins.onAssembly(new FlowableSamplePublisher<>(this, sampler, emitLast)); } /** - * Returns a {@code Flowable} that applies a specified accumulator function to the first item emitted by a source - * {@link Publisher}, then feeds the result of that function along with the second item emitted by the source - * {@code Publisher} into the same function, and so on until all items have been emitted by the source {@code Publisher}, - * emitting the result of each of these iterations. + * Returns a {@code Flowable} that emits the first value emitted by the current {@code Flowable}, then emits one value + * for each subsequent value emitted by the current {@code Flowable}. Each emission after the first is the result of + * applying the specified accumulator function to the previous emission and the corresponding value from the current {@code Flowable}. *

- * + * *

* This sort of function is sometimes called an accumulator. *

*
Backpressure:
- *
The operator honors downstream backpressure and expects the source {@code Publisher} to honor backpressure as well. + *
The operator honors downstream backpressure and expects the current {@code Flowable} to honor backpressure as well. * Violating this expectation, a {@link MissingBackpressureException} may get signaled somewhere downstream.
*
Scheduler:
*
{@code scan} does not operate by default on a particular {@link Scheduler}.
*
* * @param accumulator - * an accumulator function to be invoked on each item emitted by the source {@code Publisher}, whose + * an accumulator function to be invoked on each item emitted by the current {@code Flowable}, whose * result will be emitted to {@link Subscriber}s via {@link Subscriber#onNext onNext} and used in the * next accumulator call - * @return a {@code Flowable} that emits the results of each call to the accumulator function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code accumulator} is {@code null} * @see ReactiveX operators documentation: Scan */ @CheckReturnValue @@ -14140,19 +15051,18 @@ public final Flowable scan(@NonNull BiFunction accumulator) { } /** - * Returns a {@code Flowable} that applies a specified accumulator function to the first item emitted by a source - * {@link Publisher} and a seed value, then feeds the result of that function along with the second item emitted by - * the source {@code Publisher} into the same function, and so on until all items have been emitted by the source - * {@code Publisher}, emitting the result of each of these iterations. + * Returns a {@code Flowable} that emits the provided initial (seed) value, then emits one value for each value emitted + * by the current {@code Flowable}. Each emission after the first is the result of applying the specified accumulator + * function to the previous emission and the corresponding value from the current {@code Flowable}. *

- * + * *

* This sort of function is sometimes called an accumulator. *

- * Note that the {@code Publisher} that results from this method will emit {@code initialValue} as its first + * Note that the {@code Flowable} that results from this method will emit {@code initialValue} as its first * emitted item. *

- * Note that the {@code initialValue} is shared among all subscribers to the resulting {@code Publisher} + * Note that the {@code initialValue} is shared among all subscribers to the resulting {@code Flowable} * and may cause problems if it is mutable. To make sure each subscriber gets its own value, defer * the application of this operator via {@link #defer(Supplier)}: *


@@ -14167,8 +15077,10 @@ public final Flowable scan(@NonNull BiFunction accumulator) {
      * 
*
*
Backpressure:
- *
The operator honors downstream backpressure and expects the source {@code Publisher} to honor backpressure as well. - * Violating this expectation, a {@link MissingBackpressureException} may get signaled somewhere downstream.
+ *
The operator honors downstream backpressure and expects the current {@code Flowable} to honor backpressure as well. + * Violating this expectation, a {@link MissingBackpressureException} may get signaled somewhere downstream. + * The downstream request pattern is not preserved across this operator. + * The upstream is requested {@link #bufferSize()} - 1 upfront and 75% of {@link #bufferSize()} thereafter.
*
Scheduler:
*
{@code scan} does not operate by default on a particular {@link Scheduler}.
*
@@ -14177,11 +15089,11 @@ public final Flowable scan(@NonNull BiFunction accumulator) { * @param initialValue * the initial (seed) accumulator item * @param accumulator - * an accumulator function to be invoked on each item emitted by the source {@code Publisher}, whose + * an accumulator function to be invoked on each item emitted by the current {@code Flowable}, whose * result will be emitted to {@link Subscriber}s via {@link Subscriber#onNext onNext} and used in the * next accumulator call - * @return a {@code Flowable} that emits {@code initialValue} followed by the results of each call to the - * accumulator function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code initialValue} or {@code accumulator} is {@code null} * @see ReactiveX operators documentation: Scan */ @CheckReturnValue @@ -14194,21 +15106,22 @@ public final Flowable scan(@NonNull BiFunction accumulator) { } /** - * Returns a {@code Flowable} that applies a specified accumulator function to the first item emitted by a source - * {@link Publisher} and a seed value, then feeds the result of that function along with the second item emitted by - * the source {@code Publisher} into the same function, and so on until all items have been emitted by the source - * {@code Publisher}, emitting the result of each of these iterations. + * Returns a {@code Flowable} that emits the provided initial (seed) value, then emits one value for each value emitted + * by the current {@code Flowable}. Each emission after the first is the result of applying the specified accumulator + * function to the previous emission and the corresponding value from the current {@code Flowable}. *

- * + * *

* This sort of function is sometimes called an accumulator. *

- * Note that the {@code Publisher} that results from this method will emit the value returned by + * Note that the {@code Flowable} that results from this method will emit the value returned by * the {@code seedSupplier} as its first item. *

*
Backpressure:
- *
The operator honors downstream backpressure and expects the source {@code Publisher} to honor backpressure as well. - * Violating this expectation, a {@link MissingBackpressureException} may get signaled somewhere downstream.
+ *
The operator honors downstream backpressure and expects the current {@code Flowable} to honor backpressure as well. + * Violating this expectation, a {@link MissingBackpressureException} may get signaled somewhere downstream. + * The downstream request pattern is not preserved across this operator. + * The upstream is requested {@link #bufferSize()} - 1 upfront and 75% of {@link #bufferSize()} thereafter.
*
Scheduler:
*
{@code scanWith} does not operate by default on a particular {@link Scheduler}.
*
@@ -14217,11 +15130,11 @@ public final Flowable scan(@NonNull BiFunction accumulator) { * @param seedSupplier * a {@link Supplier} that returns the initial (seed) accumulator item for each individual {@link Subscriber} * @param accumulator - * an accumulator function to be invoked on each item emitted by the source {@code Publisher}, whose + * an accumulator function to be invoked on each item emitted by the current {@code Flowable}, whose * result will be emitted to {@code Subscriber}s via {@link Subscriber#onNext onNext} and used in the * next accumulator call - * @return a {@code Flowable} that emits {@code initialValue} followed by the results of each call to the - * accumulator function + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code seedSupplier} or {@code accumulator} is {@code null} * @see ReactiveX operators documentation: Scan */ @CheckReturnValue @@ -14235,26 +15148,25 @@ public final Flowable scan(@NonNull BiFunction accumulator) { } /** - * Forces a {@link Publisher}'s emissions and notifications to be serialized and for it to obey + * Forces the current {@code Flowable}'s emissions and notifications to be serialized and for it to obey * the {@code Publisher} contract in other ways. *

- * It is possible for a {@code Publisher} to invoke its {@link Subscriber}s' methods asynchronously, perhaps from + * It is possible for a {@link Publisher} to invoke its {@link Subscriber}s' methods asynchronously, perhaps from * different threads. This could make such a {@code Publisher} poorly-behaved, in that it might try to invoke * {@code onComplete} or {@code onError} before one of its {@code onNext} invocations, or it might call * {@code onNext} from two different threads concurrently. You can force such a {@code Publisher} to be * well-behaved and sequential by applying the {@code serialize} method to it. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code serialize} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code Publisher} that is guaranteed to be well-behaved and to make only serialized calls to - * its {@code Subscriber}s + * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: Serialize */ @CheckReturnValue @@ -14266,24 +15178,23 @@ public final Flowable serialize() { } /** - * Returns a new {@link Publisher} that multicasts (and shares a single subscription to) the original {@code Publisher}. As long as - * there is at least one {@link Subscriber} this {@code Publisher} will be subscribed and emitting data. - * When all subscribers have canceled it will cancel the source {@code Publisher}. + * Returns a new {@code Flowable} that multicasts (and shares a single subscription to) the current {@code Flowable}. As long as + * there is at least one {@link Subscriber}, the current {@code Flowable} will be subscribed and emitting data. + * When all subscribers have canceled it will cancel the current {@code Flowable}. *

* This is an alias for {@link #publish()}.{@link ConnectableFlowable#refCount() refCount()}. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure and expects the source {@code Publisher} to honor backpressure as well. + *
The operator honors backpressure and expects the current {@code Flowable} to honor backpressure as well. * If this expectation is violated, the operator will signal a {@link MissingBackpressureException} to * its {@code Subscriber}s.
*
Scheduler:
*
{@code share} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code Publisher} that upon connection causes the source {@code Publisher} to emit items - * to its {@code Subscriber}s + * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: RefCount */ @CheckReturnValue @@ -14299,16 +15210,16 @@ public final Flowable share() { * signals exactly one item or signals an {@link IllegalArgumentException} if this {@code Flowable} signals * more than one item. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@link Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure).
*
Scheduler:
*
{@code singleElement} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code Maybe} that emits the single item emitted by the source {@code Publisher} + * @return the new {@code Maybe} instance * @see ReactiveX operators documentation: First */ @CheckReturnValue @@ -14320,23 +15231,23 @@ public final Maybe singleElement() { } /** - * Returns a {@link Single} that emits the single item emitted by the source {@link Publisher}, if that {@code Publisher} - * emits only a single item, or a default item if the source {@code Publisher} emits no items. If the source - * {@code Publisher} emits more than one item, an {@link IllegalArgumentException} is signaled instead. + * Returns a {@link Single} that emits the single item emitted by the current {@code Flowable} if it + * emits only a single item, or a default item if the current {@code Flowable} emits no items. If the current + * {@code Flowable} emits more than one item, an {@link IllegalArgumentException} is signaled instead. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure).
*
Scheduler:
*
{@code single} does not operate by default on a particular {@link Scheduler}.
*
* * @param defaultItem - * a default value to emit if the source {@code Publisher} emits no item - * @return a {@code Single} that emits the single item emitted by the source {@code Publisher}, or a default item if - * the source {@code Publisher} is empty + * a default value to emit if the current {@code Flowable} emits no item + * @return the new {@code Single} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX operators documentation: First */ @CheckReturnValue @@ -14354,10 +15265,10 @@ public final Single single(@NonNull T defaultItem) { * if this {@code Flowable} completes without emitting any items a {@link NoSuchElementException} will be signaled and * if this {@code Flowable} emits more than one item, an {@link IllegalArgumentException} will be signaled. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@link Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure).
*
Scheduler:
*
{@code singleOrError} does not operate by default on a particular {@link Scheduler}.
@@ -14375,13 +15286,13 @@ public final Single singleOrError() { } /** - * Returns a {@code Flowable} that skips the first {@code count} items emitted by the source {@link Publisher} and emits + * Returns a {@code Flowable} that skips the first {@code count} items emitted by the current {@code Flowable} and emits * the remainder. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
This version of {@code skip} does not operate by default on a particular {@link Scheduler}.
@@ -14389,8 +15300,8 @@ public final Single singleOrError() { * * @param count * the number of items to skip - * @return a {@code Flowable} that is identical to the source {@code Publisher} except that it does not emit the first - * {@code count} items that the source {@code Publisher} emits + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code count} is negative * @see ReactiveX operators documentation: Skip */ @CheckReturnValue @@ -14398,21 +15309,24 @@ public final Single singleOrError() { @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final Flowable skip(long count) { - if (count <= 0L) { + if (count < 0) { + throw new IllegalArgumentException("count >= 0 expected but it was " + count); + } + if (count == 0) { return RxJavaPlugins.onAssembly(this); } return RxJavaPlugins.onAssembly(new FlowableSkip<>(this, count)); } /** - * Returns a {@code Flowable} that skips values emitted by the source {@link Publisher} before a specified time window + * Returns a {@code Flowable} that skips values emitted by the current {@code Flowable} before a specified time window * elapses. *

- * + * *

*
Backpressure:
*
The operator doesn't support backpressure as it uses time to skip an arbitrary number of elements and - * thus has to consume the source {@code Publisher} in an unbounded manner (i.e., no backpressure applied to it).
+ * thus has to consume the current {@code Flowable} in an unbounded manner (i.e., no backpressure applied to it).
*
Scheduler:
*
{@code skip} does not operate on any particular scheduler but uses the current time * from the {@code computation} {@link Scheduler}.
@@ -14422,8 +15336,8 @@ public final Flowable skip(long count) { * the length of the time window to skip * @param unit * the time unit of {@code time} - * @return a {@code Flowable} that skips values emitted by the source {@code Publisher} before the time window defined - * by {@code time} elapses and the emits the remainder + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Skip */ @CheckReturnValue @@ -14435,14 +15349,14 @@ public final Flowable skip(long time, @NonNull TimeUnit unit) { } /** - * Returns a {@code Flowable} that skips values emitted by the source {@link Publisher} before a specified time window + * Returns a {@code Flowable} that skips values emitted by the current {@code Flowable} before a specified time window * on a specified {@link Scheduler} elapses. *

- * + * *

*
Backpressure:
*
The operator doesn't support backpressure as it uses time to skip an arbitrary number of elements and - * thus has to consume the source {@code Publisher} in an unbounded manner (i.e., no backpressure applied to it).
+ * thus has to consume the current {@code Flowable} in an unbounded manner (i.e., no backpressure applied to it).
*
Scheduler:
*
You specify which {@code Scheduler} this operator will use for the timed skipping
*
@@ -14453,8 +15367,8 @@ public final Flowable skip(long time, @NonNull TimeUnit unit) { * the time unit of {@code time} * @param scheduler * the {@code Scheduler} on which the timed wait happens - * @return a {@code Flowable} that skips values emitted by the source {@code Publisher} before the time window defined - * by {@code time} and {@code scheduler} elapses, and then emits the remainder + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Skip */ @CheckReturnValue @@ -14467,16 +15381,16 @@ public final Flowable skip(long time, @NonNull TimeUnit unit, @NonNull Schedu /** * Returns a {@code Flowable} that drops a specified number of items from the end of the sequence emitted by the - * source {@link Publisher}. + * current {@code Flowable}. *

- * + * *

* This {@link Subscriber} accumulates a queue long enough to store the first {@code count} items. As more items are - * received, items are taken from the front of the queue and emitted by the returned {@code Publisher}. This causes + * received, items are taken from the front of the queue and emitted by the resulting {@code Flowable}. This causes * such items to be delayed. *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
This version of {@code skipLast} does not operate by default on a particular {@link Scheduler}.
@@ -14484,9 +15398,8 @@ public final Flowable skip(long time, @NonNull TimeUnit unit, @NonNull Schedu * * @param count * number of items to drop from the end of the source sequence - * @return a {@code Flowable} that emits the items emitted by the source {@code Publisher} except for the dropped ones - * at the end - * @throws IndexOutOfBoundsException + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException * if {@code count} is less than zero * @see ReactiveX operators documentation: SkipLast */ @@ -14496,7 +15409,7 @@ public final Flowable skip(long time, @NonNull TimeUnit unit, @NonNull Schedu @NonNull public final Flowable skipLast(int count) { if (count < 0) { - throw new IndexOutOfBoundsException("count >= 0 required but it was " + count); + throw new IllegalArgumentException("count >= 0 required but it was " + count); } if (count == 0) { return RxJavaPlugins.onAssembly(this); @@ -14505,16 +15418,16 @@ public final Flowable skipLast(int count) { } /** - * Returns a {@code Flowable} that drops items emitted by the source {@link Publisher} during a specified time window + * Returns a {@code Flowable} that drops items emitted by the current {@code Flowable} during a specified time window * before the source completes. *

- * + * *

* Note: this action will cache the latest items arriving in the specified time window. *

*
Backpressure:
*
The operator doesn't support backpressure as it uses time to skip an arbitrary number of elements and - * thus has to consume the source {@code Publisher} in an unbounded manner (i.e., no backpressure applied to it).
+ * thus has to consume the current {@code Flowable} in an unbounded manner (i.e., no backpressure applied to it). *
Scheduler:
*
{@code skipLast} does not operate on any particular scheduler but uses the current time * from the {@code computation} {@link Scheduler}.
@@ -14524,8 +15437,8 @@ public final Flowable skipLast(int count) { * the length of the time window * @param unit * the time unit of {@code time} - * @return a {@code Flowable} that drops those items emitted by the source {@code Publisher} in a time window before the - * source completes defined by {@code time} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: SkipLast */ @CheckReturnValue @@ -14537,16 +15450,16 @@ public final Flowable skipLast(long time, @NonNull TimeUnit unit) { } /** - * Returns a {@code Flowable} that drops items emitted by the source {@link Publisher} during a specified time window + * Returns a {@code Flowable} that drops items emitted by the current {@code Flowable} during a specified time window * before the source completes. *

- * + * *

* Note: this action will cache the latest items arriving in the specified time window. *

*
Backpressure:
*
The operator doesn't support backpressure as it uses time to skip an arbitrary number of elements and - * thus has to consume the source {@code Publisher} in an unbounded manner (i.e., no backpressure applied to it).
+ * thus has to consume the current {@code Flowable} in an unbounded manner (i.e., no backpressure applied to it). *
Scheduler:
*
{@code skipLast} does not operate on any particular scheduler but uses the current time * from the {@code computation} {@link Scheduler}.
@@ -14559,8 +15472,8 @@ public final Flowable skipLast(long time, @NonNull TimeUnit unit) { * @param delayError * if {@code true}, an exception signaled by the current {@code Flowable} is delayed until the regular elements are consumed * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @return a {@code Flowable} that drops those items emitted by the source {@code Publisher} in a time window before the - * source completes defined by {@code time} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: SkipLast */ @CheckReturnValue @@ -14572,16 +15485,16 @@ public final Flowable skipLast(long time, @NonNull TimeUnit unit, boolean del } /** - * Returns a {@code Flowable} that drops items emitted by the source {@link Publisher} during a specified time window + * Returns a {@code Flowable} that drops items emitted by the current {@code Flowable} during a specified time window * (defined on a specified scheduler) before the source completes. *

- * + * *

* Note: this action will cache the latest items arriving in the specified time window. *

*
Backpressure:
*
The operator doesn't support backpressure as it uses time to skip an arbitrary number of elements and - * thus has to consume the source {@code Publisher} in an unbounded manner (i.e., no backpressure applied to it).
+ * thus has to consume the current {@code Flowable} in an unbounded manner (i.e., no backpressure applied to it). *
Scheduler:
*
You specify which {@link Scheduler} this operator will use for tracking the current time
*
@@ -14592,8 +15505,8 @@ public final Flowable skipLast(long time, @NonNull TimeUnit unit, boolean del * the time unit of {@code time} * @param scheduler * the scheduler used as the time source - * @return a {@code Flowable} that drops those items emitted by the source {@code Publisher} in a time window before the - * source completes defined by {@code time} and {@code scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: SkipLast */ @CheckReturnValue @@ -14605,16 +15518,16 @@ public final Flowable skipLast(long time, @NonNull TimeUnit unit, @NonNull Sc } /** - * Returns a {@code Flowable} that drops items emitted by the source {@link Publisher} during a specified time window + * Returns a {@code Flowable} that drops items emitted by the current {@code Flowable} during a specified time window * (defined on a specified scheduler) before the source completes. *

- * + * *

* Note: this action will cache the latest items arriving in the specified time window. *

*
Backpressure:
*
The operator doesn't support backpressure as it uses time to skip an arbitrary number of elements and - * thus has to consume the source {@code Publisher} in an unbounded manner (i.e., no backpressure applied to it).
+ * thus has to consume the current {@code Flowable} in an unbounded manner (i.e., no backpressure applied to it). *
Scheduler:
*
You specify which {@link Scheduler} this operator will use to track the current time
*
@@ -14628,8 +15541,8 @@ public final Flowable skipLast(long time, @NonNull TimeUnit unit, @NonNull Sc * @param delayError * if {@code true}, an exception signaled by the current {@code Flowable} is delayed until the regular elements are consumed * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @return a {@code Flowable} that drops those items emitted by the source {@code Publisher} in a time window before the - * source completes defined by {@code time} and {@code scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: SkipLast */ @CheckReturnValue @@ -14641,16 +15554,16 @@ public final Flowable skipLast(long time, @NonNull TimeUnit unit, @NonNull Sc } /** - * Returns a {@code Flowable} that drops items emitted by the source {@link Publisher} during a specified time window + * Returns a {@code Flowable} that drops items emitted by the current {@code Flowable} during a specified time window * (defined on a specified scheduler) before the source completes. *

- * + * *

* Note: this action will cache the latest items arriving in the specified time window. *

*
Backpressure:
*
The operator doesn't support backpressure as it uses time to skip an arbitrary number of elements and - * thus has to consume the source {@code Publisher} in an unbounded manner (i.e., no backpressure applied to it).
+ * thus has to consume the current {@code Flowable} in an unbounded manner (i.e., no backpressure applied to it). *
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
@@ -14666,8 +15579,9 @@ public final Flowable skipLast(long time, @NonNull TimeUnit unit, @NonNull Sc * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped * @param bufferSize * the hint about how many elements to expect to be skipped - * @return a {@code Flowable} that drops those items emitted by the source {@code Publisher} in a time window before the - * source completes defined by {@code time} and {@code scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: SkipLast */ @CheckReturnValue @@ -14684,13 +15598,13 @@ public final Flowable skipLast(long time, @NonNull TimeUnit unit, @NonNull Sc } /** - * Returns a {@code Flowable} that skips items emitted by the source {@link Publisher} until a second {@code Publisher} emits + * Returns a {@code Flowable} that skips items emitted by the current {@code Flowable} until a second {@link Publisher} emits * an item. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code skipUntil} does not operate by default on a particular {@link Scheduler}.
@@ -14698,38 +15612,38 @@ public final Flowable skipLast(long time, @NonNull TimeUnit unit, @NonNull Sc * * @param the element type of the other {@code Publisher} * @param other - * the second {@code Publisher} that has to emit an item before the source {@code Publisher}'s elements begin - * to be mirrored by the resulting {@code Publisher} - * @return a {@code Flowable} that skips items from the source {@code Publisher} until the second {@code Publisher} emits an - * item, then emits the remaining items + * the second {@code Publisher} that has to emit an item before the current {@code Flowable}'s elements begin + * to be mirrored by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: SkipUntil */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable skipUntil(@NonNull Publisher other) { + public final <@NonNull U> Flowable skipUntil(@NonNull Publisher other) { Objects.requireNonNull(other, "other is null"); return RxJavaPlugins.onAssembly(new FlowableSkipUntil<>(this, other)); } /** - * Returns a {@code Flowable} that skips all items emitted by the source {@link Publisher} as long as a specified + * Returns a {@code Flowable} that skips all items emitted by the current {@code Flowable} as long as a specified * condition holds {@code true}, but emits all further source items as soon as the condition becomes {@code false}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code skipWhile} does not operate by default on a particular {@link Scheduler}.
*
* * @param predicate - * a function to test each item emitted from the source {@code Publisher} - * @return a {@code Flowable} that begins emitting items emitted by the source {@code Publisher} when the specified - * predicate becomes {@code false} + * a function to test each item emitted from the current {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @see ReactiveX operators documentation: SkipWhile */ @CheckReturnValue @@ -14753,13 +15667,13 @@ public final Flowable skipWhile(@NonNull Predicate predicate) { * *
*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code sorted} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code Flowable} that emits the items emitted by the source {@code Publisher} in sorted order + * @return the new {@code Flowable} instance */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @@ -14778,44 +15692,45 @@ public final Flowable sorted() { * *
*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code sorted} does not operate by default on a particular {@link Scheduler}.
*
* - * @param sortFunction - * a function that compares two items emitted by the source {@code Publisher} and returns an {@link Integer} + * @param comparator + * a function that compares two items emitted by the current {@code Flowable} and returns an {@link Integer} * that indicates their sort order - * @return a {@code Flowable} that emits the items emitted by the source {@code Publisher} in sorted order + * @throws NullPointerException if {@code comparator} is {@code null} + * @return the new {@code Flowable} instance */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable sorted(@NonNull Comparator<@NonNull ? super T> sortFunction) { - Objects.requireNonNull(sortFunction, "sortFunction"); - return toList().toFlowable().map(Functions.listSorter(sortFunction)).flatMapIterable(Functions.identity()); + public final Flowable sorted(@NonNull Comparator<@NonNull ? super T> comparator) { + Objects.requireNonNull(comparator, "comparator is null"); + return toList().toFlowable().map(Functions.listSorter(comparator)).flatMapIterable(Functions.identity()); } /** * Returns a {@code Flowable} that emits the items in a specified {@link Iterable} before it begins to emit items - * emitted by the source {@link Publisher}. + * emitted by the current {@code Flowable}. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher} + *
The operator honors backpressure from downstream. The Current {@code Flowable} * is expected to honor backpressure as well. If it violates this rule, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * {@link IllegalStateException} when the current {@code Flowable} completes. *
Scheduler:
*
{@code startWithIterable} does not operate by default on a particular {@link Scheduler}.
*
* * @param items - * an {@code Iterable} that contains the items you want the modified {@code Publisher} to emit first - * @return a {@code Flowable} that emits the items in the specified {@code Iterable} and then emits the items - * emitted by the source {@code Publisher} + * an {@code Iterable} that contains the items you want the resulting {@code Flowable} to emit first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code items} is {@code null} * @see ReactiveX operators documentation: StartWith * @see #startWithArray(Object...) * @see #startWithItem(Object) @@ -14829,24 +15744,99 @@ public final Flowable startWithIterable(@NonNull Iterable items) return concatArray(fromIterable(items), this); } + /** + * Returns a {@code Flowable} which first runs the other {@link CompletableSource} + * then the current {@code Flowable} if the other completed normally. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Flowable} honors the backpressure of the downstream consumer.
+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code CompletableSource} to run first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.FULL) + public final Flowable startWith(@NonNull CompletableSource other) { + Objects.requireNonNull(other, "other is null"); + return Flowable.concat(Completable.wrap(other).toFlowable(), this); + } + + /** + * Returns a {@code Flowable} which first runs the other {@link SingleSource} + * then the current {@code Flowable} if the other succeeded normally. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Flowable} honors the backpressure of the downstream consumer.
+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code SingleSource} to run first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.FULL) + public final Flowable startWith(@NonNull SingleSource other) { + Objects.requireNonNull(other, "other is null"); + return Flowable.concat(Single.wrap(other).toFlowable(), this); + } + + /** + * Returns a {@code Flowable} which first runs the other {@link MaybeSource} + * then the current {@code Flowable} if the other succeeded or completed normally. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Flowable} honors the backpressure of the downstream consumer.
+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code MaybeSource} to run first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.FULL) + public final Flowable startWith(@NonNull MaybeSource other) { + Objects.requireNonNull(other, "other is null"); + return Flowable.concat(Maybe.wrap(other).toFlowable(), this); + } + /** * Returns a {@code Flowable} that emits the items in a specified {@link Publisher} before it begins to emit - * items emitted by the source {@code Publisher}. + * items emitted by the current {@code Flowable}. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. Both this and the {@code other} {@code Publisher}s * are expected to honor backpressure as well. If any of then violates this rule, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * {@link IllegalStateException} when the current {@code Flowable} completes. *
Scheduler:
*
{@code startWith} does not operate by default on a particular {@link Scheduler}.
*
* * @param other * a {@code Publisher} that contains the items you want the modified {@code Publisher} to emit first - * @return a {@code Flowable} that emits the items in the specified {@code Publisher} and then emits the items - * emitted by the source {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: StartWith */ @CheckReturnValue @@ -14859,23 +15849,23 @@ public final Flowable startWith(@NonNull Publisher other) { } /** - * Returns a {@code Flowable} that emits a specified item before it begins to emit items emitted by the source - * {@link Publisher}. + * Returns a {@code Flowable} that emits a specified item before it begins to emit items emitted by the current + * {@code Flowable}. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher} + *
The operator honors backpressure from downstream. The current {@code Flowable} * is expected to honor backpressure as well. If it violates this rule, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * {@link IllegalStateException} when the current {@code Flowable} completes. *
Scheduler:
*
{@code startWithItem} does not operate by default on a particular {@link Scheduler}.
*
* * @param item * the item to emit first - * @return a {@code Flowable} that emits the specified item before it begins to emit items emitted by the source - * {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code item} is {@code null} * @see ReactiveX operators documentation: StartWith * @see #startWithArray(Object...) * @see #startWithIterable(Iterable) @@ -14891,23 +15881,23 @@ public final Flowable startWithItem(@NonNull T item) { } /** - * Returns a {@code Flowable} that emits the specified items before it begins to emit items emitted by the source - * {@link Publisher}. + * Returns a {@code Flowable} that emits the specified items before it begins to emit items emitted by the current + * {@code Flowable}. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher} + *
The operator honors backpressure from downstream. The current {@code Flowable} * is expected to honor backpressure as well. If it violates this rule, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * {@link IllegalStateException} when the current {@code Flowable} completes. *
Scheduler:
*
{@code startWithArray} does not operate by default on a particular {@link Scheduler}.
*
* * @param items * the array of values to emit first - * @return a {@code Flowable} that emits the specified items before it begins to emit items emitted by the source - * {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code items} is {@code null} * @see ReactiveX operators documentation: StartWith * @see #startWithItem(Object) * @see #startWithIterable(Iterable) @@ -14926,22 +15916,22 @@ public final Flowable startWithArray(@NonNull T... items) { } /** - * Subscribes to a {@link Publisher} and ignores {@code onNext} and {@code onComplete} emissions. + * Subscribes to the current {@code Flowable} and ignores {@code onNext} and {@code onComplete} emissions. *

* If the {@code Flowable} emits an error, it is wrapped into an * {@link io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException OnErrorNotImplementedException} * and routed to the {@link RxJavaPlugins#onError(Throwable)} handler. *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner (i.e., no + *
The operator consumes the current {@code Flowable} in an unbounded manner (i.e., no * backpressure is applied to it).
*
Scheduler:
*
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@link Disposable} reference with which the caller can stop receiving items before - * the {@code Publisher} has finished sending them + * @return the new {@link Disposable} instance that allows cancelling the flow * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, Action, DisposableContainer) */ @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) @@ -14951,26 +15941,26 @@ public final Disposable subscribe() { } /** - * Subscribes to a {@link Publisher} and provides a callback to handle the items it emits. + * Subscribes to the current {@code Flowable} and provides a callback to handle the items it emits. *

* If the {@code Flowable} emits an error, it is wrapped into an * {@link io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException OnErrorNotImplementedException} * and routed to the {@link RxJavaPlugins#onError(Throwable)} handler. *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner (i.e., no + *
The operator consumes the current {@code Flowable} in an unbounded manner (i.e., no * backpressure is applied to it).
*
Scheduler:
*
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
* * @param onNext - * the {@code Consumer} you have designed to accept emissions from the {@code Publisher} - * @return a {@link Disposable} reference with which the caller can stop receiving items before - * the {@code Publisher} has finished sending them + * the {@code Consumer} you have designed to accept emissions from the current {@code Flowable} + * @return the new {@link Disposable} instance that allows cancelling the flow * @throws NullPointerException * if {@code onNext} is {@code null} * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, Action, DisposableContainer) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @@ -14981,27 +15971,26 @@ public final Disposable subscribe(@NonNull Consumer onNext) { } /** - * Subscribes to a {@link Publisher} and provides callbacks to handle the items it emits and any error + * Subscribes to the current {@code Flowable} and provides callbacks to handle the items it emits and any error * notification it issues. *
*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner (i.e., no + *
The operator consumes the current {@code Flowable} in an unbounded manner (i.e., no * backpressure is applied to it).
*
Scheduler:
*
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
* * @param onNext - * the {@code Consumer} you have designed to accept emissions from the {@code Publisher} + * the {@code Consumer} you have designed to accept emissions from the current {@code Flowable} * @param onError * the {@code Consumer} you have designed to accept any error notification from the - * {@code Publisher} - * @return a {@link Disposable} reference with which the caller can stop receiving items before - * the {@code Publisher} has finished sending them - * @see ReactiveX operators documentation: Subscribe + * current {@code Flowable} + * @return the new {@link Disposable} instance that allows cancelling the flow * @throws NullPointerException - * if {@code onNext} is {@code null}, or - * if {@code onError} is {@code null} + * if {@code onNext} or {@code onError} is {@code null} + * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, Action, DisposableContainer) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @@ -15012,31 +16001,29 @@ public final Disposable subscribe(@NonNull Consumer onNext, @NonNull } /** - * Subscribes to a {@link Publisher} and provides callbacks to handle the items it emits and any error or + * Subscribes to the current {@code Flowable} and provides callbacks to handle the items it emits and any error or * completion notification it issues. *
*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner (i.e., no + *
The operator consumes the current {@code Flowable} in an unbounded manner (i.e., no * backpressure is applied to it).
*
Scheduler:
*
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
* * @param onNext - * the {@code Consumer} you have designed to accept emissions from the {@code Publisher} + * the {@code Consumer} you have designed to accept emissions from the current {@code Flowable} * @param onError * the {@code Consumer} you have designed to accept any error notification from the - * {@code Publisher} + * current {@code Flowable} * @param onComplete * the {@link Action} you have designed to accept a completion notification from the - * {@code Publisher} - * @return a {@link Disposable} reference with which the caller can stop receiving items before - * the {@code Publisher} has finished sending them + * the current {@code Flowable} + * @return the new {@link Disposable} instance that allows cancelling the flow * @throws NullPointerException - * if {@code onNext} is {@code null}, or - * if {@code onError} is {@code null}, or - * if {@code onComplete} is {@code null} + * if {@code onNext}, {@code onError} or {@code onComplete} is {@code null} * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, Action, DisposableContainer) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @@ -15052,18 +16039,63 @@ public final Disposable subscribe(@NonNull Consumer onNext, @NonNull subscribe(ls); - return ls; + return ls; + } + + /** + * Wraps the given onXXX callbacks into a {@link Disposable} {@link Subscriber}, + * adds it to the given {@link DisposableContainer} and ensures, that if the upstream + * terminates or this particular {@code Disposable} is disposed, the {@code Subscriber} is removed + * from the given container. + *

+ * The {@code Subscriber} will be removed after the callback for the terminal event has been invoked. + *

+ *
Backpressure:
+ *
The operator consumes the current {@code Flowable} in an unbounded manner (i.e., no + * backpressure is applied to it).
+ *
Scheduler:
+ *
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param onNext the callback for upstream items + * @param onError the callback for an upstream error if any + * @param onComplete the callback for the upstream completion if any + * @param container the {@code DisposableContainer} (such as {@link CompositeDisposable}) to add and remove the + * created {@code Disposable} {@code Subscriber} + * @return the {@code Disposable} that allows disposing the particular subscription. + * @throws NullPointerException + * if {@code onNext}, {@code onError}, + * {@code onComplete} or {@code container} is {@code null} + * @since 3.1.0 + */ + @BackpressureSupport(BackpressureKind.SPECIAL) + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Disposable subscribe( + @NonNull Consumer onNext, + @NonNull Consumer onError, + @NonNull Action onComplete, + @NonNull DisposableContainer container) { + Objects.requireNonNull(onNext, "onNext is null"); + Objects.requireNonNull(onError, "onError is null"); + Objects.requireNonNull(onComplete, "onComplete is null"); + Objects.requireNonNull(container, "container is null"); + + DisposableAutoReleaseSubscriber subscriber = new DisposableAutoReleaseSubscriber<>( + container, onNext, onError, onComplete); + container.add(subscriber); + subscribe(subscriber); + return subscriber; } @BackpressureSupport(BackpressureKind.SPECIAL) @SchedulerSupport(SchedulerSupport.NONE) @Override - public final void subscribe(@NonNull Subscriber s) { - if (s instanceof FlowableSubscriber) { - subscribe((FlowableSubscriber)s); + public final void subscribe(@NonNull Subscriber subscriber) { + if (subscriber instanceof FlowableSubscriber) { + subscribe((FlowableSubscriber)subscriber); } else { - Objects.requireNonNull(s, "s is null"); - subscribe(new StrictSubscriber<>(s)); + Objects.requireNonNull(subscriber, "subscriber is null"); + subscribe(new StrictSubscriber<>(subscriber)); } } @@ -15101,19 +16133,20 @@ public final void subscribe(@NonNull Subscriber s) { *
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.0.7 - experimental; 2.1 - beta - * @param s the {@code FlowableSubscriber} that will consume signals from this {@code Flowable} + * @param subscriber the {@code FlowableSubscriber} that will consume signals from this {@code Flowable} + * @throws NullPointerException if {@code subscriber} is {@code null} * @since 2.2 */ @BackpressureSupport(BackpressureKind.SPECIAL) @SchedulerSupport(SchedulerSupport.NONE) - public final void subscribe(@NonNull FlowableSubscriber s) { - Objects.requireNonNull(s, "s is null"); + public final void subscribe(@NonNull FlowableSubscriber subscriber) { + Objects.requireNonNull(subscriber, "subscriber is null"); try { - Subscriber z = RxJavaPlugins.onSubscribe(this, s); + Subscriber flowableSubscriber = RxJavaPlugins.onSubscribe(this, subscriber); - Objects.requireNonNull(z, "The RxJavaPlugins.onSubscribe hook returned a null FlowableSubscriber. Please check the handler provided to RxJavaPlugins.setOnFlowableSubscribe for invalid null returns. Further reading: https://github.com/ReactiveX/RxJava/wiki/Plugins"); + Objects.requireNonNull(flowableSubscriber, "The RxJavaPlugins.onSubscribe hook returned a null FlowableSubscriber. Please check the handler provided to RxJavaPlugins.setOnFlowableSubscribe for invalid null returns. Further reading: https://github.com/ReactiveX/RxJava/wiki/Plugins"); - subscribeActual(z); + subscribeActual(flowableSubscriber); } catch (NullPointerException e) { // NOPMD throw e; } catch (Throwable e) { @@ -15134,9 +16167,9 @@ public final void subscribe(@NonNull FlowableSubscriber s) { *

There is no need to call any of the plugin hooks on the current {@code Flowable} instance or * the {@code Subscriber}; all hooks and basic safeguards have been * applied by {@link #subscribe(Subscriber)} before this method gets called. - * @param s the incoming {@code Subscriber}, never {@code null} + * @param subscriber the incoming {@code Subscriber}, never {@code null} */ - protected abstract void subscribeActual(@NonNull Subscriber s); + protected abstract void subscribeActual(@NonNull Subscriber subscriber); /** * Subscribes a given {@link Subscriber} (subclass) to this {@code Flowable} and returns the given @@ -15175,16 +16208,16 @@ public final void subscribe(@NonNull FlowableSubscriber s) { } /** - * Asynchronously subscribes {@link Subscriber}s to this {@link Publisher} on the specified {@link Scheduler}. + * Asynchronously subscribes {@link Subscriber}s to the current {@code Flowable} on the specified {@link Scheduler}. *

* If there is a {@link #create(FlowableOnSubscribe, BackpressureStrategy)} type source up in the * chain, it is recommended to use {@code subscribeOn(scheduler, false)} instead * to avoid same-pool deadlock because requests may pile up behind an eager/blocking emitter. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
You specify which {@code Scheduler} this operator will use.
@@ -15192,8 +16225,8 @@ public final void subscribe(@NonNull FlowableSubscriber s) { * * @param scheduler * the {@code Scheduler} to perform subscription actions on - * @return the source {@code Publisher} modified so that its subscriptions happen on the - * specified {@code Scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: SubscribeOn * @see RxJava Threading Examples * @see #observeOn @@ -15209,17 +16242,17 @@ public final Flowable subscribeOn(@NonNull Scheduler scheduler) { } /** - * Asynchronously subscribes {@link Subscriber}s to this {@link Publisher} on the specified {@link Scheduler} + * Asynchronously subscribes {@link Subscriber}s to the current {@code Flowable} on the specified {@link Scheduler} * optionally reroutes requests from other threads to the same {@code Scheduler} thread. *

* If there is a {@link #create(FlowableOnSubscribe, BackpressureStrategy)} type source up in the * chain, it is recommended to have {@code requestOn} {@code false} to avoid same-pool deadlock * because requests may pile up behind an eager/blocking emitter. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
You specify which {@code Scheduler} this operator will use.
@@ -15230,8 +16263,8 @@ public final Flowable subscribeOn(@NonNull Scheduler scheduler) { * @param requestOn if {@code true}, requests are rerouted to the given {@code Scheduler} as well (strong pipelining) * if {@code false}, requests coming from any thread are simply forwarded to * the upstream on the same thread (weak pipelining) - * @return the source {@code Publisher} modified so that its subscriptions happen on the - * specified {@code Scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: SubscribeOn * @see RxJava Threading Examples * @see #observeOn @@ -15247,14 +16280,14 @@ public final Flowable subscribeOn(@NonNull Scheduler scheduler, boolean reque } /** - * Returns a {@code Flowable} that emits the items emitted by the source {@link Publisher} or the items of an alternate - * {@code Publisher} if the source {@code Publisher} is empty. + * Returns a {@code Flowable} that emits the items emitted by the current {@code Flowable} or the items of an alternate + * {@link Publisher} if the current {@code Flowable} is empty. *

- * + * *

*
Backpressure:
- *
If the source {@code Publisher} is empty, the alternate {@code Publisher} is expected to honor backpressure. - * If the source {@code Publisher} is non-empty, it is expected to honor backpressure as instead. + *
If the current {@code Flowable} is empty, the alternate {@code Publisher} is expected to honor backpressure. + * If the current {@code Flowable} is non-empty, it is expected to honor backpressure as instead. * In either case, if violated, a {@link MissingBackpressureException} may get * signaled somewhere downstream. *
@@ -15264,8 +16297,8 @@ public final Flowable subscribeOn(@NonNull Scheduler scheduler, boolean reque * * @param other * the alternate {@code Publisher} to subscribe to if the source does not emit any items - * @return a {@code Publisher} that emits the items emitted by the source {@code Publisher} or the items of an - * alternate {@code Publisher} if the source {@code Publisher} is empty. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 1.1.0 */ @CheckReturnValue @@ -15278,14 +16311,14 @@ public final Flowable switchIfEmpty(@NonNull Publisher other) { } /** - * Returns a new {@link Publisher} by applying a function that you supply to each item emitted by the source - * {@code Publisher} that returns a {@code Publisher}, and then emitting the items emitted by the most recently emitted + * Returns a new {@code Flowable} by applying a function that you supply to each item emitted by the current + * {@code Flowable} that returns a {@link Publisher}, and then emitting the items emitted by the most recently emitted * of these {@code Publisher}s. *

- * The resulting {@code Publisher} completes if both the upstream {@code Publisher} and the last inner {@code Publisher}, if any, complete. - * If the upstream {@code Publisher} signals an {@code onError}, the inner {@code Publisher} is canceled and the error delivered in-sequence. + * The resulting {@code Flowable} completes if both the current {@code Flowable} and the last inner {@code Publisher}, if any, complete. + * If the current {@code Flowable} signals an {@code onError}, the inner {@code Publisher} is canceled and the error delivered in-sequence. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The outer {@code Publisher} is consumed in an @@ -15298,9 +16331,10 @@ public final Flowable switchIfEmpty(@NonNull Publisher other) { * * @param the element type of the inner {@code Publisher}s and the output * @param mapper - * a function that, when applied to an item emitted by the source {@code Publisher}, returns a + * a function that, when applied to an item emitted by the current {@code Flowable}, returns a * {@code Publisher} - * @return a {@code Flowable} that emits the items emitted by the {@code Publisher} returned from applying {@code func} to the most recently emitted item emitted by the source {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap * @see #switchMapDelayError(Function) */ @@ -15308,19 +16342,19 @@ public final Flowable switchIfEmpty(@NonNull Publisher other) { @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable switchMap(@NonNull Function> mapper) { + public final <@NonNull R> Flowable switchMap(@NonNull Function> mapper) { return switchMap(mapper, bufferSize()); } /** - * Returns a new {@link Publisher} by applying a function that you supply to each item emitted by the source - * {@code Publisher} that returns a {@code Publisher}, and then emitting the items emitted by the most recently emitted + * Returns a new {@code Flowable} by applying a function that you supply to each item emitted by the current + * {@code Flowable} that returns a {@link Publisher}, and then emitting the items emitted by the most recently emitted * of these {@code Publisher}s. *

- * The resulting {@code Publisher} completes if both the upstream {@code Publisher} and the last inner {@code Publisher}, if any, complete. - * If the upstream {@code Publisher} signals an {@code onError}, the inner {@code Publisher} is canceled and the error delivered in-sequence. + * The resulting {@code Flowable} completes if both the current {@code Flowable} and the last inner {@code Publisher}, if any, complete. + * If the current {@code Flowable} signals an {@code onError}, the inner {@code Publisher} is canceled and the error delivered in-sequence. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The outer {@code Publisher} is consumed in an @@ -15333,11 +16367,13 @@ public final Flowable switchMap(@NonNull Function the element type of the inner {@code Publisher}s and the output * @param mapper - * a function that, when applied to an item emitted by the source {@code Publisher}, returns a + * a function that, when applied to an item emitted by the current {@code Flowable}, returns a * {@code Publisher} * @param bufferSize * the number of elements to prefetch from the current active inner {@code Publisher} - * @return a {@code Flowable} that emits the items emitted by the {@code Publisher} returned from applying {@code func} to the most recently emitted item emitted by the source {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: FlatMap * @see #switchMapDelayError(Function, int) */ @@ -15345,7 +16381,7 @@ public final Flowable switchMap(@NonNull Function Flowable switchMap(@NonNull Function> mapper, int bufferSize) { + public final <@NonNull R> Flowable switchMap(@NonNull Function> mapper, int bufferSize) { return switchMap0(mapper, bufferSize, false); } @@ -15354,7 +16390,7 @@ public final Flowable switchMap(@NonNull Function - * + * *

* Since a {@code CompletableSource} doesn't produce any items, the resulting reactive type of * this operator is a {@link Completable} that can only indicate successful completion or @@ -15383,6 +16419,7 @@ public final Flowable switchMap(@NonNull Function - * The resulting {@code Publisher} completes if both the upstream {@code Publisher} and the last inner {@code Publisher}, if any, complete. - * If the upstream {@code Publisher} signals an {@code onError}, the termination of the last inner {@code Publisher} will emit that error as is + * The resulting {@code Flowable} completes if both the current {@code Flowable} and the last inner {@code Publisher}, if any, complete. + * If the current {@code Flowable} signals an {@code onError}, the termination of the last inner {@code Publisher} will emit that error as is * or wrapped into a {@link CompositeException} along with the other possible errors the former inner {@code Publisher}s signaled. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The outer {@code Publisher} is consumed in an @@ -15464,9 +16502,10 @@ public final Completable switchMapCompletableDelayError(@NonNull Function the element type of the inner {@code Publisher}s and the output * @param mapper - * a function that, when applied to an item emitted by the source {@code Publisher}, returns a + * a function that, when applied to an item emitted by the current {@code Flowable}, returns a * {@code Publisher} - * @return a {@code Flowable} that emits the items emitted by the {@code Publisher} returned from applying {@code func} to the most recently emitted item emitted by the source {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap * @see #switchMap(Function) * @since 2.0 @@ -15475,20 +16514,20 @@ public final Completable switchMapCompletableDelayError(@NonNull Function Flowable switchMapDelayError(@NonNull Function> mapper) { + public final <@NonNull R> Flowable switchMapDelayError(@NonNull Function> mapper) { return switchMapDelayError(mapper, bufferSize()); } /** - * Returns a new {@link Publisher} by applying a function that you supply to each item emitted by the source - * {@code Publisher} that returns a {@code Publisher}, and then emitting the items emitted by the most recently emitted + * Returns a new {@code Flowable} by applying a function that you supply to each item emitted by the current + * {@code Flowable} that returns a {@link Publisher}, and then emitting the items emitted by the most recently emitted * of these {@code Publisher}s and delays any error until all {@code Publisher}s terminate. *

- * The resulting {@code Publisher} completes if both the upstream {@code Publisher} and the last inner {@code Publisher}, if any, complete. - * If the upstream {@code Publisher} signals an {@code onError}, the termination of the last inner {@code Publisher} will emit that error as is + * The resulting {@code Flowable} completes if both the current {@code Flowable} and the last inner {@code Publisher}, if any, complete. + * If the current {@code Flowable} signals an {@code onError}, the termination of the last inner {@code Publisher} will emit that error as is * or wrapped into a {@link CompositeException} along with the other possible errors the former inner {@code Publisher}s signaled. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The outer {@code Publisher} is consumed in an @@ -15501,11 +16540,13 @@ public final Flowable switchMapDelayError(@NonNull Function the element type of the inner {@code Publisher}s and the output * @param mapper - * a function that, when applied to an item emitted by the source {@code Publisher}, returns a + * a function that, when applied to an item emitted by the current {@code Flowable}, returns a * {@code Publisher} * @param bufferSize * the number of elements to prefetch from the current active inner {@code Publisher} - * @return a {@code Flowable} that emits the items emitted by the {@code Publisher} returned from applying {@code func} to the most recently emitted item emitted by the source {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: FlatMap * @see #switchMap(Function, int) * @since 2.0 @@ -15514,11 +16555,11 @@ public final Flowable switchMapDelayError(@NonNull Function Flowable switchMapDelayError(@NonNull Function> mapper, int bufferSize) { + public final <@NonNull R> Flowable switchMapDelayError(@NonNull Function> mapper, int bufferSize) { return switchMap0(mapper, bufferSize, true); } - Flowable switchMap0(Function> mapper, int bufferSize, boolean delayError) { + Flowable switchMap0(Function> mapper, int bufferSize, boolean delayError) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); if (this instanceof ScalarSupplier) { @@ -15538,7 +16579,7 @@ Flowable switchMap0(Function> * available while failing immediately if this {@code Flowable} or any of the * active inner {@code MaybeSource}s fail. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The main {@code Flowable} is consumed in an @@ -15561,6 +16602,7 @@ Flowable switchMap0(Function> * return a {@code MaybeSource} to replace the current active inner source * and get subscribed to. * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see #switchMapMaybeDelayError(Function) * @since 2.2 */ @@ -15568,7 +16610,7 @@ Flowable switchMap0(Function> @NonNull @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable switchMapMaybe(@NonNull Function> mapper) { + public final <@NonNull R> Flowable switchMapMaybe(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new FlowableSwitchMapMaybe<>(this, mapper, false)); } @@ -15578,7 +16620,7 @@ public final Flowable switchMapMaybe(@NonNull Function - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. The main {@code Flowable} is consumed in an @@ -15592,6 +16634,7 @@ public final Flowable switchMapMaybe(@NonNull Function Flowable switchMapMaybe(@NonNull Function Flowable switchMapMaybeDelayError(@NonNull Function> mapper) { + public final <@NonNull R> Flowable switchMapMaybeDelayError(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new FlowableSwitchMapMaybe<>(this, mapper, true)); } @@ -15610,7 +16653,7 @@ public final Flowable switchMapMaybeDelayError(@NonNull Function - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. The main {@code Flowable} is consumed in an @@ -15633,6 +16676,7 @@ public final Flowable switchMapMaybeDelayError(@NonNull Function Flowable switchMapMaybeDelayError(@NonNull Function Flowable switchMapSingle(@NonNull Function> mapper) { + public final <@NonNull R> Flowable switchMapSingle(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new FlowableSwitchMapSingle<>(this, mapper, false)); } @@ -15650,7 +16694,7 @@ public final Flowable switchMapSingle(@NonNull Function - * + * *
*
Backpressure:
*
The operator honors backpressure from downstream. The main {@code Flowable} is consumed in an @@ -15664,6 +16708,7 @@ public final Flowable switchMapSingle(@NonNull Function Flowable switchMapSingle(@NonNull Function Flowable switchMapSingleDelayError(@NonNull Function> mapper) { + public final <@NonNull R> Flowable switchMapSingleDelayError(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new FlowableSwitchMapSingle<>(this, mapper, true)); } /** - * Returns a {@code Flowable} that emits only the first {@code count} items emitted by the source {@link Publisher}. If the source emits fewer than - * {@code count} items then all of its items are emitted. + * Returns a {@code Flowable} that emits only the first {@code count} items emitted by the current {@code Flowable}. + * If the source emits fewer than {@code count} items then all of its items are emitted. *

- * + * *

- * This method returns a {@code Publisher} that will invoke a subscribing {@link Subscriber}'s + * This method returns a {@code Flowable} that will invoke a subscribing {@link Subscriber}'s * {@link Subscriber#onNext onNext} function a maximum of {@code count} times before invoking * {@link Subscriber#onComplete onComplete}. *

@@ -15691,19 +16736,19 @@ public final Flowable switchMapSingleDelayError(@NonNull Function * The operator requests at most the given {@code count} of items from upstream even - * if the downstream requests more than that. For example, given a {@code limit(5)}, + * if the downstream requests more than that. For example, given a {@code take(5)}, * if the downstream requests 1, a request of 1 is submitted to the upstream * and the operator remembers that only 4 items can be requested now on. A request * of 5 at this point will request 4 from the upstream and any subsequent requests will * be ignored. *

- * Note that requests are negotiated on an operator boundary and {@code limit}'s amount + * Note that requests are negotiated on an operator boundary and {@code take}'s amount * may not be preserved further upstream. For example, - * {@code source.observeOn(Schedulers.computation()).limit(5)} will still request the + * {@code source.observeOn(Schedulers.computation()).take(5)} will still request the * default (128) elements from the given {@code source}. *

*
Backpressure:
- *
The source {@code Publisher} is consumed in a bounded manner.
+ *
The current {@code Flowable} is consumed in a bounded manner.
*
Scheduler:
*
This version of {@code take} does not operate by default on a particular {@link Scheduler}.
*
@@ -15712,8 +16757,8 @@ public final Flowable switchMapSingleDelayError(@NonNull FunctionReactiveX operators documentation: Take */ @CheckReturnValue @@ -15734,10 +16779,10 @@ public final Flowable take(long count) { * If time runs out before the {@code Flowable} completes normally, the {@code onComplete} event will be * signaled on the default {@code computation} {@link Scheduler}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
This version of {@code take} operates by default on the {@code computation} {@code Scheduler}.
@@ -15747,7 +16792,8 @@ public final Flowable take(long count) { * the length of the time window * @param unit * the time unit of {@code time} - * @return a {@code Flowable} that emits those items emitted by the source {@code Publisher} before the time runs out + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Take */ @CheckReturnValue @@ -15765,10 +16811,10 @@ public final Flowable take(long time, @NonNull TimeUnit unit) { * If time runs out before the {@code Flowable} completes normally, the {@code onComplete} event will be * signaled on the provided {@code Scheduler}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
You specify which {@code Scheduler} this operator will use.
@@ -15780,8 +16826,8 @@ public final Flowable take(long time, @NonNull TimeUnit unit) { * the time unit of {@code time} * @param scheduler * the {@code Scheduler} used for time source - * @return a {@code Flowable} that emits those items emitted by the source {@code Publisher} before the time runs out, - * according to the specified {@code Scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Take */ @CheckReturnValue @@ -15793,10 +16839,10 @@ public final Flowable take(long time, @NonNull TimeUnit unit, @NonNull Schedu } /** - * Returns a {@code Flowable} that emits at most the last {@code count} items emitted by the source {@link Publisher}. If the source emits fewer than + * Returns a {@code Flowable} that emits at most the last {@code count} items emitted by the current {@code Flowable}. If the source emits fewer than * {@code count} items then all of its items are emitted. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream if the {@code count} is non-zero; ignores @@ -15806,11 +16852,11 @@ public final Flowable take(long time, @NonNull TimeUnit unit, @NonNull Schedu *
* * @param count - * the maximum number of items to emit from the end of the sequence of items emitted by the source - * {@code Publisher} - * @return a {@code Flowable} that emits at most the last {@code count} items emitted by the source {@code Publisher} - * @throws IndexOutOfBoundsException - * if {@code count} is less than zero + * the maximum number of items to emit from the end of the sequence of items emitted by the current + * {@code Flowable} + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException + * if {@code count} is negative * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -15819,7 +16865,7 @@ public final Flowable take(long time, @NonNull TimeUnit unit, @NonNull Schedu @NonNull public final Flowable takeLast(int count) { if (count < 0) { - throw new IndexOutOfBoundsException("count >= 0 required but it was " + count); + throw new IllegalArgumentException("count >= 0 required but it was " + count); } else if (count == 0) { return RxJavaPlugins.onAssembly(new FlowableIgnoreElements<>(this)); @@ -15831,13 +16877,13 @@ public final Flowable takeLast(int count) { } /** - * Returns a {@code Flowable} that emits at most a specified number of items from the source {@link Publisher} that were - * emitted in a specified window of time before the {@code Publisher} completed. + * Returns a {@code Flowable} that emits at most a specified number of items from the current {@code Flowable} that were + * emitted in a specified window of time before the current {@code Flowable} completed. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., no backpressure is applied to it).
*
Scheduler:
*
{@code takeLast} does not operate on any particular scheduler but uses the current time @@ -15850,8 +16896,9 @@ public final Flowable takeLast(int count) { * the length of the time window * @param unit * the time unit of {@code time} - * @return a {@code Flowable} that emits at most {@code count} items from the source {@code Publisher} that were emitted - * in a specified window of time before the {@code Publisher} completed + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code count} is negative * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -15863,14 +16910,14 @@ public final Flowable takeLast(long count, long time, @NonNull TimeUnit unit) } /** - * Returns a {@code Flowable} that emits at most a specified number of items from the source {@link Publisher} that were - * emitted in a specified window of time before the {@code Publisher} completed, where the timing information is + * Returns a {@code Flowable} that emits at most a specified number of items from the current {@code Flowable} that were + * emitted in a specified window of time before the current {@code Flowable} completed, where the timing information is * provided by a given {@link Scheduler}. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., no backpressure is applied to it).
*
Scheduler:
*
You specify which {@code Scheduler} this operator will use for tracking the current time
@@ -15884,10 +16931,9 @@ public final Flowable takeLast(long count, long time, @NonNull TimeUnit unit) * the time unit of {@code time} * @param scheduler * the {@code Scheduler} that provides the timestamps for the observed items - * @return a {@code Flowable} that emits at most {@code count} items from the source {@code Publisher} that were emitted - * in a specified window of time before the {@code Publisher} completed, where the timing information is - * provided by the given {@code scheduler} - * @throws IndexOutOfBoundsException + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException * if {@code count} is less than zero * @see ReactiveX operators documentation: TakeLast */ @@ -15900,14 +16946,14 @@ public final Flowable takeLast(long count, long time, @NonNull TimeUnit unit, } /** - * Returns a {@code Flowable} that emits at most a specified number of items from the source {@link Publisher} that were - * emitted in a specified window of time before the {@code Publisher} completed, where the timing information is + * Returns a {@code Flowable} that emits at most a specified number of items from the current {@code Flowable} that were + * emitted in a specified window of time before the current {@code Flowable} completed, where the timing information is * provided by a given {@link Scheduler}. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., no backpressure is applied to it).
*
Scheduler:
*
You specify which {@code Scheduler} this operator will use for tracking the current time
@@ -15926,11 +16972,10 @@ public final Flowable takeLast(long count, long time, @NonNull TimeUnit unit, * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped * @param bufferSize * the hint about how many elements to expect to be last - * @return a {@code Flowable} that emits at most {@code count} items from the source {@code Publisher} that were emitted - * in a specified window of time before the {@code Publisher} completed, where the timing information is - * provided by the given {@code scheduler} - * @throws IndexOutOfBoundsException - * if {@code count} is less than zero + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException + * if {@code count} is negative or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -15942,19 +16987,19 @@ public final Flowable takeLast(long count, long time, @NonNull TimeUnit unit, Objects.requireNonNull(scheduler, "scheduler is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); if (count < 0) { - throw new IndexOutOfBoundsException("count >= 0 required but it was " + count); + throw new IllegalArgumentException("count >= 0 required but it was " + count); } return RxJavaPlugins.onAssembly(new FlowableTakeLastTimed<>(this, count, time, unit, scheduler, bufferSize, delayError)); } /** - * Returns a {@code Flowable} that emits the items from the source {@link Publisher} that were emitted in a specified - * window of time before the {@code Publisher} completed. + * Returns a {@code Flowable} that emits the items from the current {@code Flowable} that were emitted in a specified + * window of time before the current {@code Flowable} completed. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., no backpressure is applied to it) but note that this may * lead to {@link OutOfMemoryError} due to internal buffer bloat. * Consider using {@link #takeLast(long, long, TimeUnit)} in this case.
@@ -15966,8 +17011,8 @@ public final Flowable takeLast(long count, long time, @NonNull TimeUnit unit, * the length of the time window * @param unit * the time unit of {@code time} - * @return a {@code Flowable} that emits the items from the source {@code Publisher} that were emitted in the window of - * time before the {@code Publisher} completed specified by {@code time} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -15979,13 +17024,13 @@ public final Flowable takeLast(long time, @NonNull TimeUnit unit) { } /** - * Returns a {@code Flowable} that emits the items from the source {@link Publisher} that were emitted in a specified - * window of time before the {@code Publisher} completed. + * Returns a {@code Flowable} that emits the items from the current {@code Flowable} that were emitted in a specified + * window of time before the current {@code Flowable} completed. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., no backpressure is applied to it) but note that this may * lead to {@link OutOfMemoryError} due to internal buffer bloat. * Consider using {@link #takeLast(long, long, TimeUnit)} in this case.
@@ -16000,8 +17045,8 @@ public final Flowable takeLast(long time, @NonNull TimeUnit unit) { * @param delayError * if {@code true}, an exception signaled by the current {@code Flowable} is delayed until the regular elements are consumed * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @return a {@code Flowable} that emits the items from the source {@code Publisher} that were emitted in the window of - * time before the {@code Publisher} completed specified by {@code time} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -16013,14 +17058,14 @@ public final Flowable takeLast(long time, @NonNull TimeUnit unit, boolean del } /** - * Returns a {@code Flowable} that emits the items from the source {@link Publisher} that were emitted in a specified - * window of time before the {@code Publisher} completed, where the timing information is provided by a specified + * Returns a {@code Flowable} that emits the items from the current {@code Flowable} that were emitted in a specified + * window of time before the current {@code Flowable} completed, where the timing information is provided by a specified * {@link Scheduler}. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., no backpressure is applied to it) but note that this may * lead to {@link OutOfMemoryError} due to internal buffer bloat. * Consider using {@link #takeLast(long, long, TimeUnit, Scheduler)} in this case.
@@ -16034,9 +17079,8 @@ public final Flowable takeLast(long time, @NonNull TimeUnit unit, boolean del * the time unit of {@code time} * @param scheduler * the {@code Scheduler} that provides the timestamps for the observed items - * @return a {@code Flowable} that emits the items from the source {@code Publisher} that were emitted in the window of - * time before the {@code Publisher} completed specified by {@code time}, where the timing information is - * provided by {@code scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -16048,14 +17092,14 @@ public final Flowable takeLast(long time, @NonNull TimeUnit unit, @NonNull Sc } /** - * Returns a {@code Flowable} that emits the items from the source {@link Publisher} that were emitted in a specified - * window of time before the {@code Publisher} completed, where the timing information is provided by a specified + * Returns a {@code Flowable} that emits the items from the current {@code Flowable} that were emitted in a specified + * window of time before the current {@code Flowable} completed, where the timing information is provided by a specified * {@link Scheduler}. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., no backpressure is applied to it) but note that this may * lead to {@link OutOfMemoryError} due to internal buffer bloat. * Consider using {@link #takeLast(long, long, TimeUnit, Scheduler)} in this case.
@@ -16072,9 +17116,8 @@ public final Flowable takeLast(long time, @NonNull TimeUnit unit, @NonNull Sc * @param delayError * if {@code true}, an exception signaled by the current {@code Flowable} is delayed until the regular elements are consumed * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @return a {@code Flowable} that emits the items from the source {@code Publisher} that were emitted in the window of - * time before the {@code Publisher} completed specified by {@code time}, where the timing information is - * provided by {@code scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -16086,14 +17129,14 @@ public final Flowable takeLast(long time, @NonNull TimeUnit unit, @NonNull Sc } /** - * Returns a {@code Flowable} that emits the items from the source {@link Publisher} that were emitted in a specified - * window of time before the {@code Publisher} completed, where the timing information is provided by a specified + * Returns a {@code Flowable} that emits the items from the current {@code Flowable} that were emitted in a specified + * window of time before the current {@code Flowable} completed, where the timing information is provided by a specified * {@link Scheduler}. *

- * + * *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., no backpressure is applied to it) but note that this may * lead to {@link OutOfMemoryError} due to internal buffer bloat. * Consider using {@link #takeLast(long, long, TimeUnit, Scheduler)} in this case.
@@ -16112,9 +17155,9 @@ public final Flowable takeLast(long time, @NonNull TimeUnit unit, @NonNull Sc * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped * @param bufferSize * the hint about how many elements to expect to be last - * @return a {@code Flowable} that emits the items from the source {@code Publisher} that were emitted in the window of - * time before the {@code Publisher} completed specified by {@code time}, where the timing information is - * provided by {@code scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -16126,10 +17169,10 @@ public final Flowable takeLast(long time, @NonNull TimeUnit unit, @NonNull Sc } /** - * Returns a {@code Flowable} that emits items emitted by the source {@link Publisher}, checks the specified predicate + * Returns a {@code Flowable} that emits items emitted by the current {@code Flowable}, checks the specified predicate * for each item, and then completes when the condition is satisfied. *

- * + * *

* The difference between this operator and {@link #takeWhile(Predicate)} is that here, the condition is * evaluated after the item is emitted. @@ -16143,9 +17186,9 @@ public final Flowable takeLast(long time, @NonNull TimeUnit unit, @NonNull Sc *

* * @param stopPredicate - * a function that evaluates an item emitted by the source {@code Publisher} and returns a {@link Boolean} - * @return a {@code Flowable} that first emits items emitted by the source {@code Publisher}, checks the specified - * condition after each item, and then completes when the condition is satisfied. + * a function that evaluates an item emitted by the current {@code Flowable} and returns a {@link Boolean} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code stopPredicate} is {@code null} * @see ReactiveX operators documentation: TakeUntil * @see Flowable#takeWhile(Predicate) * @since 1.1.0 @@ -16160,52 +17203,53 @@ public final Flowable takeUntil(@NonNull Predicate stopPredicate) } /** - * Returns a {@code Flowable} that emits the items emitted by the source {@link Publisher} until a second {@code Publisher} - * emits an item. + * Returns a {@code Flowable} that emits the items emitted by the current {@code Flowable} until a second {@link Publisher} + * emits an item or completes. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code takeUntil} does not operate by default on a particular {@link Scheduler}.
*
* * @param other - * the {@code Publisher} whose first emitted item will cause {@code takeUntil} to stop emitting items - * from the source {@code Publisher} + * the {@code Publisher} whose first emitted item or completion will cause {@code takeUntil} to stop emitting items + * from the current {@code Flowable} * @param * the type of items emitted by {@code other} - * @return a {@code Flowable} that emits the items emitted by the source {@code Publisher} until such time as {@code other} emits its first item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: TakeUntil */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable takeUntil(@NonNull Publisher other) { + public final <@NonNull U> Flowable takeUntil(@NonNull Publisher other) { Objects.requireNonNull(other, "other is null"); return RxJavaPlugins.onAssembly(new FlowableTakeUntil<>(this, other)); } /** - * Returns a {@code Flowable} that emits items emitted by the source {@link Publisher} so long as each item satisfied a + * Returns a {@code Flowable} that emits items emitted by the current {@code Flowable} so long as each item satisfied a * specified condition, and then completes as soon as this condition is not satisfied. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code takeWhile} does not operate by default on a particular {@link Scheduler}.
*
* * @param predicate - * a function that evaluates an item emitted by the source {@code Publisher} and returns a {@link Boolean} - * @return a {@code Flowable} that emits the items from the source {@code Publisher} so long as each item satisfies the - * condition defined by {@code predicate}, then completes + * a function that evaluates an item emitted by the current {@code Flowable} and returns a {@link Boolean} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @see ReactiveX operators documentation: TakeWhile * @see Flowable#takeUntil(Predicate) */ @@ -16219,13 +17263,13 @@ public final Flowable takeWhile(@NonNull Predicate predicate) { } /** - * Returns a {@code Flowable} that emits only the first item emitted by the source {@link Publisher} during sequential + * Returns a {@code Flowable} that emits only the first item emitted by the current {@code Flowable} during sequential * time windows of a specified duration. *

* This differs from {@link #throttleLast} in that this only tracks the passage of time whereas * {@link #throttleLast} ticks at scheduled intervals. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time to control data flow.
@@ -16237,7 +17281,8 @@ public final Flowable takeWhile(@NonNull Predicate predicate) { * time to wait before emitting another item after emitting the last item * @param unit * the unit of time of {@code windowDuration} - * @return a {@code Flowable} that performs the throttle operation + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Sample * @see RxJava wiki: Backpressure */ @@ -16250,13 +17295,13 @@ public final Flowable throttleFirst(long windowDuration, @NonNull TimeUnit un } /** - * Returns a {@code Flowable} that emits only the first item emitted by the source {@link Publisher} during sequential + * Returns a {@code Flowable} that emits only the first item emitted by the current {@code Flowable} during sequential * time windows of a specified duration, where the windows are managed by a specified {@link Scheduler}. *

* This differs from {@link #throttleLast} in that this only tracks the passage of time whereas * {@link #throttleLast} ticks at scheduled intervals. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time to control data flow.
@@ -16271,7 +17316,8 @@ public final Flowable throttleFirst(long windowDuration, @NonNull TimeUnit un * @param scheduler * the {@code Scheduler} to use internally to manage the timers that handle timeout for each * event - * @return a {@code Flowable} that performs the throttle operation + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Sample * @see RxJava wiki: Backpressure */ @@ -16282,17 +17328,60 @@ public final Flowable throttleFirst(long windowDuration, @NonNull TimeUnit un public final Flowable throttleFirst(long skipDuration, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new FlowableThrottleFirstTimed<>(this, skipDuration, unit, scheduler)); + return RxJavaPlugins.onAssembly(new FlowableThrottleFirstTimed<>(this, skipDuration, unit, scheduler, null)); + } + + /** + * Returns a {@code Flowable} that emits only the first item emitted by the current {@code Flowable} during sequential + * time windows of a specified duration, where the windows are managed by a specified {@link Scheduler}. + *

+ * This differs from {@link #throttleLast} in that this only tracks the passage of time whereas + * {@link #throttleLast} ticks at scheduled intervals. + *

+ * + *

+ *
Backpressure:
+ *
This operator does not support backpressure as it uses time to control data flow.
+ *
Scheduler:
+ *
You specify which {@code Scheduler} this operator will use.
+ *
+ * + * @param skipDuration + * time to wait before emitting another item after emitting the last item + * @param unit + * the unit of time of {@code skipDuration} + * @param scheduler + * the {@code Scheduler} to use internally to manage the timers that handle timeout for each + * event + * @param onDropped + * called when an item doesn't get delivered to the downstream + * + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} or {@code onDropped} is {@code null} + * @see ReactiveX operators documentation: Sample + * @see RxJava wiki: Backpressure + * @since 3.1.6 - Experimental + */ + @CheckReturnValue + @NonNull + @BackpressureSupport(BackpressureKind.ERROR) + @SchedulerSupport(SchedulerSupport.CUSTOM) + @Experimental + public final Flowable throttleFirst(long skipDuration, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + Objects.requireNonNull(onDropped, "onDropped is null"); + return RxJavaPlugins.onAssembly(new FlowableThrottleFirstTimed<>(this, skipDuration, unit, scheduler, onDropped)); } /** - * Returns a {@code Flowable} that emits only the last item emitted by the source {@link Publisher} during sequential + * Returns a {@code Flowable} that emits only the last item emitted by the current {@code Flowable} during sequential * time windows of a specified duration. *

* This differs from {@link #throttleFirst} in that this ticks along at a scheduled interval whereas * {@link #throttleFirst} does not tick, it just tracks the passage of time. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time to control data flow.
@@ -16301,11 +17390,12 @@ public final Flowable throttleFirst(long skipDuration, @NonNull TimeUnit unit *
* * @param intervalDuration - * duration of windows within which the last item emitted by the source {@code Publisher} will be + * duration of windows within which the last item emitted by the current {@code Flowable} will be * emitted * @param unit * the unit of time of {@code intervalDuration} - * @return a {@code Flowable} that performs the throttle operation + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Sample * @see RxJava wiki: Backpressure * @see #sample(long, TimeUnit) @@ -16319,13 +17409,13 @@ public final Flowable throttleLast(long intervalDuration, @NonNull TimeUnit u } /** - * Returns a {@code Flowable} that emits only the last item emitted by the source {@link Publisher} during sequential + * Returns a {@code Flowable} that emits only the last item emitted by the current {@code Flowable} during sequential * time windows of a specified duration, where the duration is governed by a specified {@link Scheduler}. *

* This differs from {@link #throttleFirst(long, TimeUnit, Scheduler)} in that this ticks along at a scheduled interval whereas * {@code throttleFirst} does not tick, it just tracks the passage of time. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time to control data flow.
@@ -16334,14 +17424,15 @@ public final Flowable throttleLast(long intervalDuration, @NonNull TimeUnit u *
* * @param intervalDuration - * duration of windows within which the last item emitted by the source {@code Publisher} will be + * duration of windows within which the last item emitted by the current {@code Flowable} will be * emitted * @param unit * the unit of time of {@code intervalDuration} * @param scheduler * the {@code Scheduler} to use internally to manage the timers that handle timeout for each * event - * @return a {@code Flowable} that performs the throttle operation + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Sample * @see RxJava wiki: Backpressure * @see #sample(long, TimeUnit, Scheduler) @@ -16354,12 +17445,53 @@ public final Flowable throttleLast(long intervalDuration, @NonNull TimeUnit u return sample(intervalDuration, unit, scheduler); } + /** + * Returns a {@code Flowable} that emits only the last item emitted by the current {@code Flowable} during sequential + * time windows of a specified duration, where the duration is governed by a specified {@link Scheduler}. + *

+ * This differs from {@link #throttleFirst(long, TimeUnit, Scheduler)} in that this ticks along at a scheduled interval whereas + * {@code throttleFirst} does not tick, it just tracks the passage of time. + *

+ * + *

+ *
Backpressure:
+ *
This operator does not support backpressure as it uses time to control data flow.
+ *
Scheduler:
+ *
You specify which {@code Scheduler} this operator will use.
+ *
+ * + * @param intervalDuration + * duration of windows within which the last item emitted by the current {@code Flowable} will be + * emitted + * @param unit + * the unit of time of {@code intervalDuration} + * @param scheduler + * the {@code Scheduler} to use internally to manage the timers that handle timeout for each + * event + * @param onDropped + * called with the current entry when it has been replaced by a new one + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} or {@code onDropped} is {@code null} + * @see ReactiveX operators documentation: Sample + * @see RxJava wiki: Backpressure + * @see #sample(long, TimeUnit, Scheduler) + * @since 3.1.6 - Experimental + */ + @CheckReturnValue + @BackpressureSupport(BackpressureKind.ERROR) + @SchedulerSupport(SchedulerSupport.CUSTOM) + @NonNull + @Experimental + public final Flowable throttleLast(long intervalDuration, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { + return sample(intervalDuration, unit, scheduler, false, onDropped); + } + /** * Throttles items from the upstream {@code Flowable} by first emitting the next * item from upstream, then periodically emitting the latest item (if any) when * the specified timeout elapses between them. *

- * + * *

* Unlike the option with {@link #throttleLatest(long, TimeUnit, boolean)}, the very last item being held back * (if any) is not emitted when the upstream completes. @@ -16380,6 +17512,7 @@ public final Flowable throttleLast(long intervalDuration, @NonNull TimeUnit u * before trying to emit the latest item from upstream again * @param unit the time unit * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @since 2.2 * @see #throttleLatest(long, TimeUnit, boolean) * @see #throttleLatest(long, TimeUnit, Scheduler) @@ -16397,7 +17530,7 @@ public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit) { * item from upstream, then periodically emitting the latest item (if any) when * the specified timeout elapses between them. *

- * + * *

* If no items were emitted from the upstream during this timeout phase, the next * upstream item is emitted immediately and the timeout window starts from then. @@ -16419,6 +17552,7 @@ public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit) { * a timeout window active or not. If {@code false}, the very last * upstream item is ignored and the flow terminates. * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see #throttleLatest(long, TimeUnit, Scheduler, boolean) * @since 2.2 */ @@ -16435,7 +17569,7 @@ public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, bo * item from upstream, then periodically emitting the latest item (if any) when * the specified timeout elapses between them. *

- * + * *

* Unlike the option with {@link #throttleLatest(long, TimeUnit, Scheduler, boolean)}, the very last item being held back * (if any) is not emitted when the upstream completes. @@ -16458,6 +17592,7 @@ public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, bo * @param scheduler the {@code Scheduler} where the timed wait and latest item * emission will be performed * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see #throttleLatest(long, TimeUnit, Scheduler, boolean) * @since 2.2 */ @@ -16474,7 +17609,7 @@ public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, @N * item from upstream, then periodically emitting the latest item (if any) when * the specified timeout elapses between them. *

- * + * *

* If no items were emitted from the upstream during this timeout phase, the next * upstream item is emitted immediately and the timeout window starts from then. @@ -16498,6 +17633,7 @@ public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, @N * a timeout window active or not. If {@code false}, the very last * upstream item is ignored and the flow terminates. * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -16507,18 +17643,72 @@ public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, @N public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new FlowableThrottleLatest<>(this, timeout, unit, scheduler, emitLast)); + return RxJavaPlugins.onAssembly(new FlowableThrottleLatest<>(this, timeout, unit, scheduler, emitLast, null)); + } + + /** + * Throttles items from the upstream {@code Flowable} by first emitting the next + * item from upstream, then periodically emitting the latest item (if any) when + * the specified timeout elapses between them, invoking the consumer for any dropped item. + *

+ * + *

+ * If no items were emitted from the upstream during this timeout phase, the next + * upstream item is emitted immediately and the timeout window starts from then. + *

+ *
Backpressure:
+ *
This operator does not support backpressure as it uses time to control data flow. + * If the downstream is not ready to receive items, a + * {@link io.reactivex.rxjava3.exceptions.MissingBackpressureException MissingBackpressureException} + * will be signaled.
+ *
Scheduler:
+ *
You specify which {@link Scheduler} this operator will use.
+ *
Error handling:
+ *
+ * If the upstream signals an {@code onError} or {@code onDropped} callback crashes, + * the error is delivered immediately to the downstream. If both happen, a {@link CompositeException} + * is created, containing both the upstream and the callback error. + * If the {@code onDropped} callback crashes during cancellation, the exception is forwarded + * to the global error handler via {@link RxJavaPlugins#onError(Throwable)}. + *
+ *
+ * @param timeout the time to wait after an item emission towards the downstream + * before trying to emit the latest item from upstream again + * @param unit the time unit + * @param scheduler the {@code Scheduler} where the timed wait and latest item + * emission will be performed + * @param emitLast If {@code true}, the very last item from the upstream will be emitted + * immediately when the upstream completes, regardless if there is + * a timeout window active or not. If {@code false}, the very last + * upstream item is ignored and the flow terminates. + * @param onDropped called when an item is replaced by a newer item that doesn't get delivered + * to the downstream, including the very last item if {@code emitLast} is {@code false} + * and the current undelivered item when the sequence gets canceled. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code onDropped} is {@code null} + * @since 3.1.6 - Experimental + */ + @CheckReturnValue + @NonNull + @BackpressureSupport(BackpressureKind.ERROR) + @SchedulerSupport(SchedulerSupport.CUSTOM) + @Experimental + public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast, @NonNull Consumer onDropped) { + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + Objects.requireNonNull(onDropped, "onDropped is null"); + return RxJavaPlugins.onAssembly(new FlowableThrottleLatest<>(this, timeout, unit, scheduler, emitLast, onDropped)); } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher}, except that it drops items emitted by the - * source {@code Publisher} that are followed by newer items before a timeout value expires. The timer resets on + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, except that it drops items emitted by the + * current {@code Flowable} that are followed by newer items before a timeout value expires. The timer resets on * each emission (alias to {@link #debounce(long, TimeUnit)}). *

- * Note: If items keep being emitted by the source {@code Publisher} faster than the timeout then no items - * will be emitted by the resulting {@code Publisher}. + * Note: If items keep being emitted by the current {@code Flowable} faster than the timeout then no items + * will be emitted by the resulting {@code Flowable}. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time to control data flow.
@@ -16527,13 +17717,13 @@ public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, @N *
* * @param timeout - * the length of the window of time that must pass after the emission of an item from the source - * {@code Publisher} in which that {@code Publisher} emits no items in order for the item to be emitted by the - * resulting {@code Publisher} + * the length of the window of time that must pass after the emission of an item from the current + * {@code Flowable} in which it emits no items in order for the item to be emitted by the + * resulting {@code Flowable} * @param unit * the unit of time for the specified {@code timeout} - * @return a {@code Flowable} that filters out items from the source {@code Publisher} that are too quickly followed by - * newer items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Debounce * @see RxJava wiki: Backpressure * @see #debounce(long, TimeUnit) @@ -16547,14 +17737,14 @@ public final Flowable throttleWithTimeout(long timeout, @NonNull TimeUnit uni } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher}, except that it drops items emitted by the - * source {@code Publisher} that are followed by newer items before a timeout value expires on a specified + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, except that it drops items emitted by the + * current {@code Flowable} that are followed by newer items before a timeout value expires on a specified * {@link Scheduler}. The timer resets on each emission (alias to {@link #debounce(long, TimeUnit, Scheduler)}). *

- * Note: If items keep being emitted by the source {@code Publisher} faster than the timeout then no items - * will be emitted by the resulting {@code Publisher}. + * Note: If items keep being emitted by the current {@code Flowable} faster than the timeout then no items + * will be emitted by the resulting {@code Flowable}. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time to control data flow.
@@ -16563,16 +17753,16 @@ public final Flowable throttleWithTimeout(long timeout, @NonNull TimeUnit uni *
* * @param timeout - * the length of the window of time that must pass after the emission of an item from the source - * {@code Publisher} in which that {@code Publisher} emits no items in order for the item to be emitted by the - * resulting {@code Publisher} + * the length of the window of time that must pass after the emission of an item from the current + * {@code Flowable} in which it emits no items in order for the item to be emitted by the + * resulting {@code Flowable} * @param unit * the unit of time for the specified {@code timeout} * @param scheduler * the {@code Scheduler} to use internally to manage the timers that handle the timeout for each * item - * @return a {@code Flowable} that filters out items from the source {@code Publisher} that are too quickly followed by - * newer items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Debounce * @see RxJava wiki: Backpressure * @see #debounce(long, TimeUnit, Scheduler) @@ -16585,21 +17775,64 @@ public final Flowable throttleWithTimeout(long timeout, @NonNull TimeUnit uni return debounce(timeout, unit, scheduler); } + /** + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, except that it drops items emitted by the + * current {@code Flowable} that are followed by newer items before a timeout value expires on a specified + * {@link Scheduler}. The timer resets on each emission (alias to {@link #debounce(long, TimeUnit, Scheduler, Consumer)}). + *

+ * Note: If items keep being emitted by the current {@code Flowable} faster than the timeout then no items + * will be emitted by the resulting {@code Flowable}. + *

+ * + *

+ *
Backpressure:
+ *
This operator does not support backpressure as it uses time to control data flow.
+ *
Scheduler:
+ *
You specify which {@code Scheduler} this operator will use.
+ *
+ * + * @param timeout + * the length of the window of time that must pass after the emission of an item from the current + * {@code Flowable} in which it emits no items in order for the item to be emitted by the + * resulting {@code Flowable} + * @param unit + * the unit of time for the specified {@code timeout} + * @param scheduler + * the {@code Scheduler} to use internally to manage the timers that handle the timeout for each + * item + * @param onDropped + * called with the current entry when it has been replaced by a new one + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} or {@code onDropped} is {@code null} + * @see ReactiveX operators documentation: Debounce + * @see RxJava wiki: Backpressure + * @see #debounce(long, TimeUnit, Scheduler, Consumer) + * @since 3.1.6 - Experimental + */ + @CheckReturnValue + @BackpressureSupport(BackpressureKind.ERROR) + @SchedulerSupport(SchedulerSupport.CUSTOM) + @NonNull + @Experimental + public final Flowable throttleWithTimeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { + return debounce(timeout, unit, scheduler, onDropped); + } + /** * Returns a {@code Flowable} that emits records of the time interval between consecutive items emitted by the - * source {@link Publisher}. + * current {@code Flowable}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code timeInterval} does not operate on any particular scheduler but uses the current time * from the {@code computation} {@link Scheduler}.
*
* - * @return a {@code Flowable} that emits time interval information items + * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: TimeInterval */ @CheckReturnValue @@ -16612,12 +17845,12 @@ public final Flowable> timeInterval() { /** * Returns a {@code Flowable} that emits records of the time interval between consecutive items emitted by the - * source {@link Publisher}, where this interval is computed on a specified {@link Scheduler}. + * current {@code Flowable}, where this interval is computed on a specified {@link Scheduler}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code timeInterval} does not operate on any particular scheduler but uses the current time @@ -16626,7 +17859,8 @@ public final Flowable> timeInterval() { * * @param scheduler * the {@code Scheduler} used to compute time intervals - * @return a {@code Flowable} that emits time interval information items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: TimeInterval */ @CheckReturnValue @@ -16639,12 +17873,12 @@ public final Flowable> timeInterval(@NonNull Scheduler scheduler) { /** * Returns a {@code Flowable} that emits records of the time interval between consecutive items emitted by the - * source {@link Publisher}. + * current {@code Flowable}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code timeInterval} does not operate on any particular scheduler but uses the current time @@ -16652,7 +17886,8 @@ public final Flowable> timeInterval(@NonNull Scheduler scheduler) { *
* * @param unit the time unit for the current time - * @return a {@code Flowable} that emits time interval information items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: TimeInterval */ @CheckReturnValue @@ -16665,12 +17900,12 @@ public final Flowable> timeInterval(@NonNull TimeUnit unit) { /** * Returns a {@code Flowable} that emits records of the time interval between consecutive items emitted by the - * source {@link Publisher}, where this interval is computed on a specified {@link Scheduler}. + * current {@code Flowable}, where this interval is computed on a specified {@link Scheduler}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code timeInterval} does not operate on any particular scheduler but uses the current time @@ -16680,7 +17915,8 @@ public final Flowable> timeInterval(@NonNull TimeUnit unit) { * @param unit the time unit for the current time * @param scheduler * the {@code Scheduler} used to compute time intervals - * @return a {@code Flowable} that emits time interval information items + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: TimeInterval */ @CheckReturnValue @@ -16694,20 +17930,20 @@ public final Flowable> timeInterval(@NonNull TimeUnit unit, @NonNull Sc } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher}, but notifies {@link Subscriber}s of a - * {@link TimeoutException} if an item emitted by the source {@code Publisher} doesn't arrive within a window of - * time after the emission of the previous item, where that period of time is measured by a {@code Publisher} that + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, but notifies {@link Subscriber}s of a + * {@link TimeoutException} if an item emitted by the current {@code Flowable} doesn't arrive within a window of + * time after the emission of the previous item, where that period of time is measured by a {@link Publisher} that * is a function of the previous item. *

- * + * *

* Note: The arrival of the first source item is never timed out. *

*
Backpressure:
*
The operator honors backpressure from downstream. The {@code Publisher} * sources are expected to honor backpressure as well. - * If any of the source {@code Publisher}s violate this, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * If any of the current {@code Flowable}s violate this, it may throw an + * {@link IllegalStateException} when the current {@code Flowable} completes.
*
Scheduler:
*
This version of {@code timeout} operates by default on the {@code immediate} {@link Scheduler}.
*
@@ -16715,36 +17951,35 @@ public final Flowable> timeInterval(@NonNull TimeUnit unit, @NonNull Sc * @param * the timeout value type (ignored) * @param itemTimeoutIndicator - * a function that returns a {@code Publisher} for each item emitted by the source - * {@code Publisher} and that determines the timeout window for the subsequent item - * @return a {@code Flowable} that mirrors the source {@code Publisher}, but notifies {@code Subscriber}s of a - * {@code TimeoutException} if an item emitted by the source {@code Publisher} takes longer to arrive than - * the time window defined by the selector for the previously emitted item + * a function that returns a {@code Publisher} for each item emitted by the current + * {@code Flowable} and that determines the timeout window for the subsequent item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code itemTimeoutIndicator} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable timeout(@NonNull Function> itemTimeoutIndicator) { + public final <@NonNull V> Flowable timeout(@NonNull Function> itemTimeoutIndicator) { return timeout0(null, itemTimeoutIndicator, null); } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher}, but that switches to a fallback {@code Publisher} if - * an item emitted by the source {@code Publisher} doesn't arrive within a window of time after the emission of the + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, but that switches to a fallback {@link Publisher} if + * an item emitted by the current {@code Flowable} doesn't arrive within a window of time after the emission of the * previous item, where that period of time is measured by a {@code Publisher} that is a function of the previous * item. *

- * + * *

* Note: The arrival of the first source item is never timed out. *

*
Backpressure:
*
The operator honors backpressure from downstream. The {@code Publisher} * sources are expected to honor backpressure as well. - * If any of the source {@code Publisher}s violate this, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * If any of the current {@code Flowable}s violate this, it may throw an + * {@link IllegalStateException} when the current {@code Flowable} completes.
*
Scheduler:
*
This version of {@code timeout} operates by default on the {@code immediate} {@link Scheduler}.
*
@@ -16752,33 +17987,32 @@ public final Flowable timeout(@NonNull Function * the timeout value type (ignored) * @param itemTimeoutIndicator - * a function that returns a {@code Publisher}, for each item emitted by the source {@code Publisher}, that + * a function that returns a {@code Publisher}, for each item emitted by the current {@code Flowable}, that * determines the timeout window for the subsequent item - * @param other - * the fallback {@code Publisher} to switch to if the source {@code Publisher} times out - * @return a {@code Flowable} that mirrors the source {@code Publisher}, but switches to mirroring a fallback {@code Publisher} - * if an item emitted by the source {@code Publisher} takes longer to arrive than the time window defined - * by the selector for the previously emitted item + * @param fallback + * the fallback {@code Publisher} to switch to if the current {@code Flowable} times out + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code itemTimeoutIndicator} or {@code fallback} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable timeout(@NonNull Function> itemTimeoutIndicator, @NonNull Publisher other) { - Objects.requireNonNull(other, "other is null"); - return timeout0(null, itemTimeoutIndicator, other); + public final <@NonNull V> Flowable timeout(@NonNull Function> itemTimeoutIndicator, @NonNull Publisher fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return timeout0(null, itemTimeoutIndicator, fallback); } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher} but applies a timeout policy for each emitted + * Returns a {@code Flowable} that mirrors the current {@code Flowable} but applies a timeout policy for each emitted * item. If the next item isn't emitted within the specified timeout duration starting from its predecessor, - * the resulting {@code Publisher} terminates and notifies {@link Subscriber}s of a {@link TimeoutException}. + * the resulting {@code Flowable} terminates and notifies {@link Subscriber}s of a {@link TimeoutException}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
This version of {@code timeout} operates by default on the {@code computation} {@link Scheduler}.
@@ -16786,102 +18020,103 @@ public final Flowable timeout(@NonNull FunctionReactiveX operators documentation: Timeout */ @CheckReturnValue @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Flowable timeout(long timeout, @NonNull TimeUnit timeUnit) { - return timeout0(timeout, timeUnit, null, Schedulers.computation()); + public final Flowable timeout(long timeout, @NonNull TimeUnit unit) { + return timeout0(timeout, unit, null, Schedulers.computation()); } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher} but applies a timeout policy for each emitted + * Returns a {@code Flowable} that mirrors the current {@code Flowable} but applies a timeout policy for each emitted * item. If the next item isn't emitted within the specified timeout duration starting from its predecessor, - * the source {@code Publisher} is disposed and resulting {@code Publisher} begins instead to mirror a fallback {@code Publisher}. + * the current {@code Flowable} is disposed and the resulting {@code Flowable} begins instead to mirror a fallback {@link Publisher}. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The {@code Publisher} * sources are expected to honor backpressure as well. - * If any of the source {@code Publisher}s violate this, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * If any of the current {@code Flowable}s violate this, it may throw an + * {@link IllegalStateException} when the current {@code Flowable} completes.
*
Scheduler:
*
This version of {@code timeout} operates by default on the {@code computation} {@link Scheduler}.
*
* * @param timeout * maximum duration between items before a timeout occurs - * @param timeUnit + * @param unit * the unit of time that applies to the {@code timeout} argument - * @param other + * @param fallback * the fallback {@code Publisher} to use in case of a timeout - * @return the source {@code Publisher} modified to switch to the fallback {@code Publisher} in case of a timeout + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code fallback} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.COMPUTATION) - public final Flowable timeout(long timeout, @NonNull TimeUnit timeUnit, @NonNull Publisher other) { - Objects.requireNonNull(other, "other is null"); - return timeout0(timeout, timeUnit, other, Schedulers.computation()); + public final Flowable timeout(long timeout, @NonNull TimeUnit unit, @NonNull Publisher fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return timeout0(timeout, unit, fallback, Schedulers.computation()); } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher} but applies a timeout policy for each emitted + * Returns a {@code Flowable} that mirrors the current {@code Flowable} but applies a timeout policy for each emitted * item using a specified {@link Scheduler}. If the next item isn't emitted within the specified timeout duration - * starting from its predecessor, the source {@code Publisher} is disposed and resulting {@code Publisher} begins - * instead to mirror a fallback {@code Publisher}. + * starting from its predecessor, the current {@code Flowable} is disposed and the resulting {@code Flowable} begins + * instead to mirror a fallback {@link Publisher}. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The {@code Publisher} * sources are expected to honor backpressure as well. - * If any of the source {@code Publisher}s violate this, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * If any of the current {@code Flowable}s violate this, it may throw an + * {@link IllegalStateException} when the current {@code Flowable} completes.
*
Scheduler:
*
You specify which {@code Scheduler} this operator will use.
*
* * @param timeout * maximum duration between items before a timeout occurs - * @param timeUnit + * @param unit * the unit of time that applies to the {@code timeout} argument * @param scheduler * the {@code Scheduler} to run the timeout timers on - * @param other + * @param fallback * the {@code Publisher} to use as the fallback in case of a timeout - * @return the source {@code Publisher} modified so that it will switch to the fallback {@code Publisher} in case of a - * timeout + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code fallback} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Flowable timeout(long timeout, @NonNull TimeUnit timeUnit, @NonNull Scheduler scheduler, @NonNull Publisher other) { - Objects.requireNonNull(other, "other is null"); - return timeout0(timeout, timeUnit, other, scheduler); + public final Flowable timeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Publisher fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return timeout0(timeout, unit, fallback, scheduler); } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher} but applies a timeout policy for each emitted + * Returns a {@code Flowable} that mirrors the current {@code Flowable} but applies a timeout policy for each emitted * item, where this policy is governed by a specified {@link Scheduler}. If the next item isn't emitted within the - * specified timeout duration starting from its predecessor, the resulting {@code Publisher} terminates and + * specified timeout duration starting from its predecessor, the resulting {@code Flowable} terminates and * notifies {@link Subscriber}s of a {@link TimeoutException}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
You specify which {@code Scheduler} this operator will use.
@@ -16889,28 +18124,28 @@ public final Flowable timeout(long timeout, @NonNull TimeUnit timeUnit, @NonN * * @param timeout * maximum duration between items before a timeout occurs - * @param timeUnit + * @param unit * the unit of time that applies to the {@code timeout} argument * @param scheduler * the {@code Scheduler} to run the timeout timers on - * @return the source {@code Publisher} modified to notify {@code Subscriber}s of a {@code TimeoutException} in case of a - * timeout + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Flowable timeout(long timeout, @NonNull TimeUnit timeUnit, @NonNull Scheduler scheduler) { - return timeout0(timeout, timeUnit, null, scheduler); + public final Flowable timeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + return timeout0(timeout, unit, null, scheduler); } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher}, but notifies {@link Subscriber}s of a - * {@link TimeoutException} if either the first item emitted by the source {@code Publisher} or any subsequent item - * doesn't arrive within time windows defined by other {@code Publisher}s. + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, but notifies {@link Subscriber}s of a + * {@link TimeoutException} if either the first item emitted by the current {@code Flowable} or any subsequent item + * doesn't arrive within time windows defined by other {@link Publisher}s. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. Both this and the returned {@code Publisher}s @@ -16928,36 +18163,35 @@ public final Flowable timeout(long timeout, @NonNull TimeUnit timeUnit, @NonN * a function that returns a {@code Publisher} that determines the timeout window for the first source * item * @param itemTimeoutIndicator - * a function that returns a {@code Publisher} for each item emitted by the source {@code Publisher} and that + * a function that returns a {@code Publisher} for each item emitted by the current {@code Flowable} and that * determines the timeout window in which the subsequent source item must arrive in order to * continue the sequence - * @return a {@code Flowable} that mirrors the source {@code Publisher}, but notifies {@code Subscriber}s of a - * {@code TimeoutException} if either the first item or any subsequent item doesn't arrive within - * the time windows specified by the timeout selectors + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code firstTimeoutIndicator} or {@code itemTimeoutIndicator} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable timeout(@NonNull Publisher firstTimeoutIndicator, - @NonNull Function> itemTimeoutIndicator) { + public final <@NonNull U, @NonNull V> Flowable timeout(@NonNull Publisher firstTimeoutIndicator, + @NonNull Function> itemTimeoutIndicator) { Objects.requireNonNull(firstTimeoutIndicator, "firstTimeoutIndicator is null"); return timeout0(firstTimeoutIndicator, itemTimeoutIndicator, null); } /** - * Returns a {@code Flowable} that mirrors the source {@link Publisher}, but switches to a fallback {@code Publisher} if either - * the first item emitted by the source {@code Publisher} or any subsequent item doesn't arrive within time windows + * Returns a {@code Flowable} that mirrors the current {@code Flowable}, but switches to a fallback {@link Publisher} if either + * the first item emitted by the current {@code Flowable} or any subsequent item doesn't arrive within time windows * defined by other {@code Publisher}s. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream. The {@code Publisher} * sources are expected to honor backpressure as well. - * If any of the source {@code Publisher}s violate this, it may throw an - * {@link IllegalStateException} when the source {@code Publisher} completes.
+ * If any of the current {@code Flowable}s violate this, it may throw an + * {@link IllegalStateException} when the current {@code Flowable} completes.
*
Scheduler:
*
{@code timeout} does not operate by default on any {@link Scheduler}.
*
@@ -16970,61 +18204,58 @@ public final Flowable timeout(@NonNull Publisher firstTimeoutIndica * a function that returns a {@code Publisher} which determines the timeout window for the first source * item * @param itemTimeoutIndicator - * a function that returns a {@code Publisher} for each item emitted by the source {@code Publisher} and that + * a function that returns a {@code Publisher} for each item emitted by the current {@code Flowable} and that * determines the timeout window in which the subsequent source item must arrive in order to * continue the sequence - * @param other - * the fallback {@code Publisher} to switch to if the source {@code Publisher} times out - * @return a {@code Flowable} that mirrors the source {@code Publisher}, but switches to the {@code other} {@code Publisher} if - * either the first item emitted by the source {@code Publisher} or any subsequent item doesn't arrive - * within time windows defined by the timeout selectors - * @throws NullPointerException - * if {@code itemTimeoutIndicator} is {@code null} + * @param fallback + * the fallback {@code Publisher} to switch to if the current {@code Flowable} times out + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code firstTimeoutIndicator}, {@code itemTimeoutIndicator} or {@code fallback} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable timeout( + public final <@NonNull U, @NonNull V> Flowable timeout( @NonNull Publisher firstTimeoutIndicator, - @NonNull Function> itemTimeoutIndicator, - @NonNull Publisher other) { + @NonNull Function> itemTimeoutIndicator, + @NonNull Publisher fallback) { Objects.requireNonNull(firstTimeoutIndicator, "firstTimeoutIndicator is null"); - Objects.requireNonNull(other, "other is null"); - return timeout0(firstTimeoutIndicator, itemTimeoutIndicator, other); + Objects.requireNonNull(fallback, "fallback is null"); + return timeout0(firstTimeoutIndicator, itemTimeoutIndicator, fallback); } - private Flowable timeout0(long timeout, TimeUnit timeUnit, Publisher other, + private Flowable timeout0(long timeout, TimeUnit unit, Publisher fallback, Scheduler scheduler) { - Objects.requireNonNull(timeUnit, "timeUnit is null"); + Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new FlowableTimeoutTimed<>(this, timeout, timeUnit, scheduler, other)); + return RxJavaPlugins.onAssembly(new FlowableTimeoutTimed<>(this, timeout, unit, scheduler, fallback)); } - private Flowable timeout0( + private <@NonNull U, @NonNull V> Flowable timeout0( Publisher firstTimeoutIndicator, - Function> itemTimeoutIndicator, - Publisher other) { + Function> itemTimeoutIndicator, + Publisher fallback) { Objects.requireNonNull(itemTimeoutIndicator, "itemTimeoutIndicator is null"); - return RxJavaPlugins.onAssembly(new FlowableTimeout<>(this, firstTimeoutIndicator, itemTimeoutIndicator, other)); + return RxJavaPlugins.onAssembly(new FlowableTimeout<>(this, firstTimeoutIndicator, itemTimeoutIndicator, fallback)); } /** - * Returns a {@code Flowable} that emits each item emitted by the source {@link Publisher}, wrapped in a + * Returns a {@code Flowable} that emits each item emitted by the current {@code Flowable}, wrapped in a * {@link Timed} object. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code timestamp} does not operate on any particular scheduler but uses the current time * from the {@code computation} {@link Scheduler}.
*
* - * @return a {@code Flowable} that emits timestamped items from the source {@code Publisher} + * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: Timestamp */ @CheckReturnValue @@ -17036,13 +18267,13 @@ public final Flowable> timestamp() { } /** - * Returns a {@code Flowable} that emits each item emitted by the source {@link Publisher}, wrapped in a + * Returns a {@code Flowable} that emits each item emitted by the current {@code Flowable}, wrapped in a * {@link Timed} object whose timestamps are provided by a specified {@link Scheduler}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
This operator does not operate on any particular scheduler but uses the current time @@ -17051,8 +18282,8 @@ public final Flowable> timestamp() { * * @param scheduler * the {@code Scheduler} to use as a time source - * @return a {@code Flowable} that emits timestamped items from the source {@code Publisher} with timestamps provided by - * the {@code scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Timestamp */ @CheckReturnValue @@ -17064,13 +18295,13 @@ public final Flowable> timestamp(@NonNull Scheduler scheduler) { } /** - * Returns a {@code Flowable} that emits each item emitted by the source {@link Publisher}, wrapped in a + * Returns a {@code Flowable} that emits each item emitted by the current {@code Flowable}, wrapped in a * {@link Timed} object. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
{@code timestamp} does not operate on any particular scheduler but uses the current time @@ -17078,7 +18309,8 @@ public final Flowable> timestamp(@NonNull Scheduler scheduler) { *
* * @param unit the time unit for the current time - * @return a {@code Flowable} that emits timestamped items from the source {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Timestamp */ @CheckReturnValue @@ -17090,13 +18322,13 @@ public final Flowable> timestamp(@NonNull TimeUnit unit) { } /** - * Returns a {@code Flowable} that emits each item emitted by the source {@link Publisher}, wrapped in a + * Returns a {@code Flowable} that emits each item emitted by the current {@code Flowable}, wrapped in a * {@link Timed} object whose timestamps are provided by a specified {@link Scheduler}. *

- * + * *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
This operator does not operate on any particular scheduler but uses the current time @@ -17106,8 +18338,8 @@ public final Flowable> timestamp(@NonNull TimeUnit unit) { * @param unit the time unit for the current time * @param scheduler * the {@code Scheduler} to use as a time source - * @return a {@code Flowable} that emits timestamped items from the source {@code Publisher} with timestamps provided by - * the {@code scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Timestamp */ @CheckReturnValue @@ -17134,13 +18366,13 @@ public final Flowable> timestamp(@NonNull TimeUnit unit, @NonNull Sched * @param the resulting object type * @param converter the function that receives the current {@code Flowable} instance and returns a value * @return the converted value - * @throws NullPointerException if converter is {@code null} + * @throws NullPointerException if {@code converter} is {@code null} * @since 2.2 */ @CheckReturnValue @BackpressureSupport(BackpressureKind.SPECIAL) @SchedulerSupport(SchedulerSupport.NONE) - public final R to(@NonNull FlowableConverter converter) { + public final <@NonNull R> R to(@NonNull FlowableConverter converter) { return Objects.requireNonNull(converter, "converter is null").apply(this); } @@ -17148,12 +18380,12 @@ public final R to(@NonNull FlowableConverter converter) { * Returns a {@link Single} that emits a single item, a list composed of all the items emitted by the * finite upstream source {@link Publisher}. *

- * + * *

* Normally, a {@code Publisher} that returns multiple items will do so by invoking its {@link Subscriber}'s - * {@link Subscriber#onNext onNext} method for each such item. You can change this behavior, instructing the - * {@code Publisher} to compose a list of all of these items and then to invoke the {@code Subscriber}'s {@code onNext} - * function once, passing it the entire list, by calling the {@code Publisher}'s {@code toList} method prior to + * {@link Subscriber#onNext onNext} method for each such item. You can change this behavior by having the + * operator compose a list of all of these items and then to invoke the {@link SingleObserver}'s {@code onSuccess} + * method once, passing it the entire list, by calling the {@code Flowable}'s {@code toList} method prior to * calling its {@link #subscribe} method. *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated list to @@ -17161,14 +18393,13 @@ public final R to(@NonNull FlowableConverter converter) { * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code toList} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@code Single} that emits a single item: a {@link List} containing all of the items emitted by the source - * {@code Publisher} + * @return the new {@code Single} instance * @see ReactiveX operators documentation: To */ @CheckReturnValue @@ -17183,12 +18414,12 @@ public final Single> toList() { * Returns a {@link Single} that emits a single item, a list composed of all the items emitted by the * finite source {@link Publisher}. *

- * + * *

* Normally, a {@code Publisher} that returns multiple items will do so by invoking its {@link Subscriber}'s - * {@link Subscriber#onNext onNext} method for each such item. You can change this behavior, instructing the - * {@code Publisher} to compose a list of all of these items and then to invoke the {@code Subscriber}'s {@code onNext} - * function once, passing it the entire list, by calling the {@code Publisher}'s {@code toList} method prior to + * {@link Subscriber#onNext onNext} method for each such item. You can change this behavior by having the + * operator compose a list of all of these items and then to invoke the {@link SingleObserver}'s {@code onSuccess} + * method once, passing it the entire list, by calling the {@code Flowable}'s {@code toList} method prior to * calling its {@link #subscribe} method. *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated list to @@ -17196,7 +18427,7 @@ public final Single> toList() { * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code toList} does not operate by default on a particular {@link Scheduler}.
@@ -17204,8 +18435,8 @@ public final Single> toList() { * * @param capacityHint * the number of elements expected from the current {@code Flowable} - * @return a {@code Single} that emits a single item: a {@link List} containing all of the items emitted by the source - * {@code Publisher} + * @return the new {@code Single} instance + * @throws IllegalArgumentException if {@code capacityHint} is non-positive * @see ReactiveX operators documentation: To */ @CheckReturnValue @@ -17221,12 +18452,12 @@ public final Single> toList(int capacityHint) { * Returns a {@link Single} that emits a single item, a list composed of all the items emitted by the * finite source {@link Publisher}. *

- * + * *

* Normally, a {@code Publisher} that returns multiple items will do so by invoking its {@link Subscriber}'s - * {@link Subscriber#onNext onNext} method for each such item. You can change this behavior, instructing the - * {@code Publisher} to compose a list of all of these items and then to invoke the {@code Subscriber}'s {@code onNext} - * function once, passing it the entire list, by calling the {@code Publisher}'s {@code toList} method prior to + * {@link Subscriber#onNext onNext} method for each such item. You can change this behavior by having the + * operator compose a collection of all of these items and then to invoke the {@link SingleObserver}'s {@code onSuccess} + * method once, passing it the entire collection, by calling the {@code Flowable}'s {@code toList} method prior to * calling its {@link #subscribe} method. *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated collection to @@ -17234,7 +18465,7 @@ public final Single> toList(int capacityHint) { * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code toList} does not operate by default on a particular {@link Scheduler}.
@@ -17243,15 +18474,15 @@ public final Single> toList(int capacityHint) { * @param the subclass of a collection of Ts * @param collectionSupplier * the {@link Supplier} returning the collection (for each individual {@code Subscriber}) to be filled in - * @return a {@code Single} that emits a single item: a {@link Collection} (subclass) containing all of the items emitted by the source - * {@code Publisher} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code collectionSupplier} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final > Single toList(@NonNull Supplier collectionSupplier) { + public final <@NonNull U extends Collection> Single toList(@NonNull Supplier collectionSupplier) { Objects.requireNonNull(collectionSupplier, "collectionSupplier is null"); return RxJavaPlugins.onAssembly(new FlowableToListSingle<>(this, collectionSupplier)); } @@ -17260,7 +18491,7 @@ public final > Single toList(@NonNull Supplie * Returns a {@link Single} that emits a single {@link HashMap} containing all items emitted by the finite source {@link Publisher}, * mapped by the keys returned by a specified {@code keySelector} function. *

- * + * *

* If more than one source item maps to the same key, the {@code HashMap} will contain the latest of those items. *

@@ -17269,7 +18500,7 @@ public final > Single toList(@NonNull Supplie * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code toMap} does not operate by default on a particular {@link Scheduler}.
@@ -17278,15 +18509,15 @@ public final > Single toList(@NonNull Supplie * @param the key type of the Map * @param keySelector * the function that extracts the key from a source item to be used in the {@code HashMap} - * @return a {@code Single} that emits a single item: a {@code HashMap} containing the mapped items from the source - * {@code Publisher} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) - public final Single> toMap(@NonNull Function keySelector) { + public final <@NonNull K> Single> toMap(@NonNull Function keySelector) { Objects.requireNonNull(keySelector, "keySelector is null"); return collect(HashMapSupplier.asSupplier(), Functions.toMapKeySelector(keySelector)); } @@ -17295,7 +18526,7 @@ public final Single> toMap(@NonNull Function - * + * *

* If more than one source item maps to the same key, the {@code HashMap} will contain a single entry that * corresponds to the latest of those items. @@ -17305,7 +18536,7 @@ public final Single> toMap(@NonNull Function *

Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code toMap} does not operate by default on a particular {@link Scheduler}.
@@ -17317,15 +18548,15 @@ public final Single> toMap(@NonNull FunctionReactiveX operators documentation: To */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) - public final Single> toMap(@NonNull Function keySelector, @NonNull Function valueSelector) { + public final <@NonNull K, @NonNull V> Single> toMap(@NonNull Function keySelector, @NonNull Function valueSelector) { Objects.requireNonNull(keySelector, "keySelector is null"); Objects.requireNonNull(valueSelector, "valueSelector is null"); return collect(HashMapSupplier.asSupplier(), Functions.toMapKeyValueSelector(keySelector, valueSelector)); @@ -17335,14 +18566,14 @@ public final Single> toMap(@NonNull Function - * + * *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated map to * be emitted. Sources that are infinite and never complete will never emit anything through this * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code toMap} does not operate by default on a particular {@link Scheduler}.
@@ -17356,15 +18587,15 @@ public final Single> toMap(@NonNull FunctionReactiveX operators documentation: To */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) - public final Single> toMap(@NonNull Function keySelector, + public final <@NonNull K, @NonNull V> Single> toMap(@NonNull Function keySelector, @NonNull Function valueSelector, @NonNull Supplier> mapSupplier) { Objects.requireNonNull(keySelector, "keySelector is null"); @@ -17376,7 +18607,7 @@ public final Single> toMap(@NonNull Function - * + * *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated map to * be emitted. Sources that are infinite and never complete will never emit anything through this @@ -17391,15 +18622,15 @@ public final Single> toMap(@NonNull Function the key type of the Map * @param keySelector * the function that extracts the key from the source items to be used as key in the {@code HashMap} - * @return a {@code Single} that emits a single item: a {@code HashMap} that contains an {@code ArrayList} of items mapped from - * the source {@code Publisher} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single>> toMultimap(@NonNull Function keySelector) { + public final <@NonNull K> Single>> toMultimap(@NonNull Function keySelector) { Function valueSelector = Functions.identity(); Supplier>> mapSupplier = HashMapSupplier.asSupplier(); Function> collectionFactory = ArrayListSupplier.asFunction(); @@ -17411,14 +18642,14 @@ public final Single>> toMultimap(@NonNull Function - * + * *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated map to * be emitted. Sources that are infinite and never complete will never emit anything through this * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code toMultimap} does not operate by default on a particular {@link Scheduler}.
@@ -17430,15 +18661,15 @@ public final Single>> toMultimap(@NonNull FunctionReactiveX operators documentation: To */ @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single>> toMultimap(@NonNull Function keySelector, @NonNull Function valueSelector) { + public final <@NonNull K, @NonNull V> Single>> toMultimap(@NonNull Function keySelector, @NonNull Function valueSelector) { Supplier>> mapSupplier = HashMapSupplier.asSupplier(); Function> collectionFactory = ArrayListSupplier.asFunction(); return toMultimap(keySelector, valueSelector, mapSupplier, collectionFactory); @@ -17449,14 +18680,14 @@ public final Single>> toMultimap(@NonNull Function - * + * *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated map to * be emitted. Sources that are infinite and never complete will never emit anything through this * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code toMultimap} does not operate by default on a particular {@link Scheduler}.
@@ -17472,15 +18703,15 @@ public final Single>> toMultimap(@NonNull FunctionReactiveX operators documentation: To */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) - public final Single>> toMultimap( + public final <@NonNull K, @NonNull V> Single>> toMultimap( @NonNull Function keySelector, @NonNull Function valueSelector, @NonNull Supplier>> mapSupplier, @@ -17497,14 +18728,14 @@ public final Single>> toMultimap( * contains an {@link ArrayList} of values, extracted by a specified {@code valueSelector} function from items * emitted by the finite source {@link Publisher} and keyed by the {@code keySelector} function. *

- * + * *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated map to * be emitted. Sources that are infinite and never complete will never emit anything through this * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code toMultimap} does not operate by default on a particular {@link Scheduler}.
@@ -17518,15 +18749,15 @@ public final Single>> toMultimap( * the function that extracts a value from the source items to be used as the value in the {@code Map} * @param mapSupplier * the function that returns a {@code Map} instance to be used - * @return a {@code Single} that emits a single item: a {@code Map} that contains a list items mapped from the source - * {@code Publisher} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code keySelector}, {@code valueSelector} or {@code mapSupplier} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single>> toMultimap( + public final <@NonNull K, @NonNull V> Single>> toMultimap( @NonNull Function keySelector, @NonNull Function valueSelector, @NonNull Supplier>> mapSupplier @@ -17563,20 +18794,19 @@ public final Observable toObservable() { * all other items emitted by this {@code Flowable}, no items will be emitted and the * sequence is terminated with a {@link ClassCastException}. *

- * + * *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated list to * be emitted. Sources that are infinite and never complete will never emit anything through this * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code toSortedList} does not operate by default on a particular {@link Scheduler}.
*
- * @return a {@code Single} that emits a {@code List} that contains the items emitted by the source {@code Publisher} in - * sorted order + * @return the new {@code Single} instance * @see ReactiveX operators documentation: To */ @CheckReturnValue @@ -17591,24 +18821,24 @@ public final Single> toSortedList() { * Returns a {@link Single} that emits a {@link List} that contains the items emitted by the finite source {@link Publisher}, in a * sorted order based on a specified comparison function. *

- * + * *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated list to * be emitted. Sources that are infinite and never complete will never emit anything through this * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code toSortedList} does not operate by default on a particular {@link Scheduler}.
*
* * @param comparator - * a function that compares two items emitted by the source {@code Publisher} and returns an {@code int} + * a function that compares two items emitted by the current {@code Flowable} and returns an {@code int} * that indicates their sort order - * @return a {@code Single} that emits a {@code List} that contains the items emitted by the source {@code Publisher} in - * sorted order + * @return the new {@code Single} instance + * @throws NullPointerException if {@code comparator} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @@ -17624,26 +18854,27 @@ public final Single> toSortedList(@NonNull Comparator compara * Returns a {@link Single} that emits a {@link List} that contains the items emitted by the finite source {@link Publisher}, in a * sorted order based on a specified comparison function. *

- * + * *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated list to * be emitted. Sources that are infinite and never complete will never emit anything through this * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code toSortedList} does not operate by default on a particular {@link Scheduler}.
*
* * @param comparator - * a function that compares two items emitted by the source {@code Publisher} and returns an {@code int} + * a function that compares two items emitted by the current {@code Flowable} and returns an {@code int} * that indicates their sort order * @param capacityHint * the initial capacity of the {@link ArrayList} used to accumulate items before sorting - * @return a {@code Single} that emits a {@code List} that contains the items emitted by the source {@code Publisher} in - * sorted order + * @return the new {@code Single} instance + * @throws NullPointerException if {@code comparator} is {@code null} + * @throws IllegalArgumentException if {@code capacityHint} is non-positive * @see ReactiveX operators documentation: To * @since 2.0 */ @@ -17665,14 +18896,14 @@ public final Single> toSortedList(@NonNull Comparator compara * all other items emitted by this {@code Flowable}, no items will be emitted and the * sequence is terminated with a {@link ClassCastException}. *

- * + * *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated list to * be emitted. Sources that are infinite and never complete will never emit anything through this * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Backpressure:
- *
The operator honors backpressure from downstream and consumes the source {@code Publisher} in an + *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an * unbounded manner (i.e., without applying backpressure to it).
*
Scheduler:
*
{@code toSortedList} does not operate by default on a particular {@link Scheduler}.
@@ -17680,8 +18911,8 @@ public final Single> toSortedList(@NonNull Comparator compara * * @param capacityHint * the initial capacity of the {@link ArrayList} used to accumulate items before sorting - * @return a {@code Single} that emits a {@code List} that contains the items emitted by the source {@code Publisher} in - * sorted order + * @return the new {@code Single} instance + * @throws IllegalArgumentException if {@code capacityHint} is non-positive * @see ReactiveX operators documentation: To * @since 2.0 */ @@ -17694,11 +18925,15 @@ public final Single> toSortedList(int capacityHint) { } /** - * Modifies the source {@link Publisher} so that subscribers will cancel it on a specified - * {@link Scheduler}. + * Cancels the current {@code Flowable} asynchronously by invoking {@link Subscription#cancel()} + * on the specified {@link Scheduler}. + *

+ * The operator suppresses signals from the current {@code Flowable} immediately when the + * downstream cancels the flow because the actual cancellation itself could take an arbitrary amount of time + * to take effect and make the flow stop producing items. *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Publisher}'s backpressure + *
The operator doesn't interfere with backpressure which is determined by the current {@code Flowable}'s backpressure * behavior.
*
Scheduler:
*
You specify which {@code Scheduler} this operator will use.
@@ -17706,8 +18941,8 @@ public final Single> toSortedList(int capacityHint) { * * @param scheduler * the {@code Scheduler} to perform cancellation actions on - * @return the source {@code Publisher} modified so that its cancellations happen on the specified - * {@code Scheduler} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: SubscribeOn */ @CheckReturnValue @@ -17720,19 +18955,19 @@ public final Flowable unsubscribeOn(@NonNull Scheduler scheduler) { } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping windows, each containing {@code count} items. When the source - * {@code Publisher} completes or encounters an error, the resulting {@code Publisher} emits the current window and - * propagates the notification from the source {@code Publisher}. + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping windows, each containing {@code count} items. When the current + * {@code Flowable} completes or encounters an error, the resulting {@code Flowable} emits the current window and + * propagates the notification from the current {@code Flowable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window will only contain one element. The behavior is * a trade-off between no-dataloss and ensuring upstream cancellation can happen. *

*
Backpressure:
- *
The operator honors backpressure of its inner and outer subscribers, however, the inner {@code Publisher} uses an + *
The operator honors backpressure of its inner and outer subscribers, however, the inner {@code Flowable} uses an * unbounded buffer that may hold at most {@code count} elements.
*
Scheduler:
*
This version of {@code window} does not operate by default on a particular {@link Scheduler}.
@@ -17740,9 +18975,8 @@ public final Flowable unsubscribeOn(@NonNull Scheduler scheduler) { * * @param count * the maximum size of each window before it should be emitted - * @return a {@code Flowable} that emits connected, non-overlapping windows, each containing at most - * {@code count} items from the source {@code Publisher} - * @throws IllegalArgumentException if either count is non-positive + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -17754,12 +18988,12 @@ public final Flowable> window(long count) { } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits windows every {@code skip} items, each containing no more than {@code count} items. When - * the source {@code Publisher} completes or encounters an error, the resulting {@code Publisher} emits the current window - * and propagates the notification from the source {@code Publisher}. + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits windows every {@code skip} items, each containing no more than {@code count} items. When + * the current {@code Flowable} completes or encounters an error, the resulting {@code Flowable} emits the current window + * and propagates the notification from the current {@code Flowable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -17767,7 +19001,7 @@ public final Flowable> window(long count) { * a trade-off between no-dataloss and ensuring upstream cancellation can happen under some race conditions. *

*
Backpressure:
- *
The operator honors backpressure of its inner and outer subscribers, however, the inner {@code Publisher} uses an + *
The operator honors backpressure of its inner and outer subscribers, however, the inner {@code Flowable} uses an * unbounded buffer that may hold at most {@code count} elements.
*
Scheduler:
*
This version of {@code window} does not operate by default on a particular {@link Scheduler}.
@@ -17778,9 +19012,8 @@ public final Flowable> window(long count) { * @param skip * how many items need to be skipped before starting a new window. Note that if {@code skip} and * {@code count} are equal this is the same operation as {@link #window(long)}. - * @return a {@code Flowable} that emits windows every {@code skip} items containing at most {@code count} items - * from the source {@code Publisher} - * @throws IllegalArgumentException if either count or skip is non-positive + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code count} or {@code skip} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -17792,12 +19025,12 @@ public final Flowable> window(long count, long skip) { } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits windows every {@code skip} items, each containing no more than {@code count} items. When - * the source {@code Publisher} completes or encounters an error, the resulting {@code Publisher} emits the current window - * and propagates the notification from the source {@code Publisher}. + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits windows every {@code skip} items, each containing no more than {@code count} items. When + * the current {@code Flowable} completes or encounters an error, the resulting {@code Flowable} emits the current window + * and propagates the notification from the current {@code Flowable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -17805,7 +19038,7 @@ public final Flowable> window(long count, long skip) { * a trade-off between no-dataloss and ensuring upstream cancellation can happen under some race conditions. *

*
Backpressure:
- *
The operator honors backpressure of its inner and outer subscribers, however, the inner {@code Publisher} uses an + *
The operator honors backpressure of its inner and outer subscribers, however, the inner {@code Flowable} uses an * unbounded buffer that may hold at most {@code count} elements.
*
Scheduler:
*
This version of {@code window} does not operate by default on a particular {@link Scheduler}.
@@ -17818,9 +19051,8 @@ public final Flowable> window(long count, long skip) { * {@code count} are equal this is the same operation as {@link #window(long)}. * @param bufferSize * the capacity hint for the buffer in the inner windows - * @return a {@code Flowable} that emits windows every {@code skip} items containing at most {@code count} items - * from the source {@code Publisher} - * @throws IllegalArgumentException if either count or skip is non-positive + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code count}, {@code skip} or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -17835,13 +19067,13 @@ public final Flowable> window(long count, long skip, int bufferSize) } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} starts a new window periodically, as determined by the {@code timeskip} argument. It emits - * each window after a fixed timespan, specified by the {@code timespan} argument. When the source - * {@code Publisher} completes or {@code Publisher} completes or encounters an error, the resulting {@code Publisher} emits the - * current window and propagates the notification from the source {@code Publisher}. + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} starts a new window periodically, as determined by the {@code timeskip} argument. It emits + * each window after a fixed timespan, specified by the {@code timespan} argument. When the current + * {@code Flowable} completes or encounters an error, the resulting {@code Flowable} emits the + * current window and propagates the notification from the current {@code Flowable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -17849,9 +19081,9 @@ public final Flowable> window(long count, long skip, int bufferSize) * a trade-off for ensuring upstream cancellation can happen under some race conditions. *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner. - * The returned {@code Publisher} doesn't support backpressure as it uses - * time to control the creation of windows. The returned inner {@code Publisher}s honor + *
The operator consumes the current {@code Flowable} in an unbounded manner. + * The resulting {@code Flowable} doesn't support backpressure as it uses + * time to control the creation of windows. The emitted inner {@code Flowable}s honor * backpressure but have an unbounded inner buffer that may lead to {@link OutOfMemoryError} * if left unconsumed.
*
Scheduler:
@@ -17864,7 +19096,8 @@ public final Flowable> window(long count, long skip, int bufferSize) * the period of time after which a new window will be created * @param unit * the unit of time that applies to the {@code timespan} and {@code timeskip} arguments - * @return a {@code Flowable} that emits new windows periodically as a fixed timespan elapses + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -17876,13 +19109,13 @@ public final Flowable> window(long timespan, long timeskip, @NonNull } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} starts a new window periodically, as determined by the {@code timeskip} argument. It emits - * each window after a fixed timespan, specified by the {@code timespan} argument. When the source - * {@code Publisher} completes or {@code Publisher} completes or encounters an error, the resulting {@code Publisher} emits the - * current window and propagates the notification from the source {@code Publisher}. + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} starts a new window periodically, as determined by the {@code timeskip} argument. It emits + * each window after a fixed timespan, specified by the {@code timespan} argument. When the current + * {@code Flowable} completes or encounters an error, the resulting {@code Flowable} emits the + * current window and propagates the notification from the current {@code Flowable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -17890,9 +19123,9 @@ public final Flowable> window(long timespan, long timeskip, @NonNull * a trade-off for ensuring upstream cancellation can happen under some race conditions. *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner. - * The returned {@code Publisher} doesn't support backpressure as it uses - * time to control the creation of windows. The returned inner {@code Publisher}s honor + *
The operator consumes the current {@code Flowable} in an unbounded manner. + * The resulting {@code Flowable} doesn't support backpressure as it uses + * time to control the creation of windows. The returned inner {@code Flowable}s honor * backpressure but have an unbounded inner buffer that may lead to {@link OutOfMemoryError} * if left unconsumed.
*
Scheduler:
@@ -17907,7 +19140,8 @@ public final Flowable> window(long timespan, long timeskip, @NonNull * the unit of time that applies to the {@code timespan} and {@code timeskip} arguments * @param scheduler * the {@code Scheduler} to use when determining the end and start of a window - * @return a {@code Flowable} that emits new windows periodically as a fixed timespan elapses + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -17919,13 +19153,13 @@ public final Flowable> window(long timespan, long timeskip, @NonNull } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} starts a new window periodically, as determined by the {@code timeskip} argument. It emits - * each window after a fixed timespan, specified by the {@code timespan} argument. When the source - * {@code Publisher} completes or {@code Publisher} completes or encounters an error, the resulting {@code Publisher} emits the - * current window and propagates the notification from the source {@code Publisher}. + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} starts a new window periodically, as determined by the {@code timeskip} argument. It emits + * each window after a fixed timespan, specified by the {@code timespan} argument. When the current + * {@code Flowable} completes or encounters an error, the resulting {@code Flowable} emits the + * current window and propagates the notification from the current {@code Flowable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -17933,9 +19167,9 @@ public final Flowable> window(long timespan, long timeskip, @NonNull * a trade-off for ensuring upstream cancellation can happen under some race conditions. *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner. - * The returned {@code Publisher} doesn't support backpressure as it uses - * time to control the creation of windows. The returned inner {@code Publisher}s honor + *
The operator consumes the current {@code Flowable} in an unbounded manner. + * The resulting {@code Flowable} doesn't support backpressure as it uses + * time to control the creation of windows. The returned inner {@code Flowable}s honor * backpressure but have an unbounded inner buffer that may lead to {@link OutOfMemoryError} * if left unconsumed.
*
Scheduler:
@@ -17952,7 +19186,9 @@ public final Flowable> window(long timespan, long timeskip, @NonNull * the {@code Scheduler} to use when determining the end and start of a window * @param bufferSize * the capacity hint for the buffer in the inner windows - * @return a {@code Flowable} that emits new windows periodically as a fixed timespan elapses + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code timespan}, {@code timeskip} or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -17969,12 +19205,12 @@ public final Flowable> window(long timespan, long timeskip, @NonNull } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping windows, each of a fixed duration specified by the - * {@code timespan} argument. When the source {@code Publisher} completes or encounters an error, the resulting - * {@code Publisher} emits the current window and propagates the notification from the source {@code Publisher}. + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping windows, each of a fixed duration specified by the + * {@code timespan} argument. When the current {@code Flowable} completes or encounters an error, the resulting + * {@code Flowable} emits the current window and propagates the notification from the current {@code Flowable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -17982,9 +19218,9 @@ public final Flowable> window(long timespan, long timeskip, @NonNull * a trade-off for ensuring upstream cancellation can happen under some race conditions. *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner. - * The returned {@code Publisher} doesn't support backpressure as it uses - * time to control the creation of windows. The returned inner {@code Publisher}s honor + *
The operator consumes the current {@code Flowable} in an unbounded manner. + * The resulting {@code Flowable} doesn't support backpressure as it uses + * time to control the creation of windows. The emitted inner {@code Flowable}s honor * backpressure and may hold up to {@code count} elements at most.
*
Scheduler:
*
This version of {@code window} operates by default on the {@code computation} {@link Scheduler}.
@@ -17995,8 +19231,8 @@ public final Flowable> window(long timespan, long timeskip, @NonNull * new window * @param unit * the unit of time that applies to the {@code timespan} argument - * @return a {@code Flowable} that emits connected, non-overlapping windows representing items emitted by the - * source {@code Publisher} during fixed, consecutive durations + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -18008,13 +19244,13 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit) } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping windows, each of a fixed duration as specified by the + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping windows, each of a fixed duration as specified by the * {@code timespan} argument or a maximum size as specified by the {@code count} argument (whichever is - * reached first). When the source {@code Publisher} completes or encounters an error, the resulting {@code Publisher} - * emits the current window and propagates the notification from the source {@code Publisher}. + * reached first). When the current {@code Flowable} completes or encounters an error, the resulting {@code Flowable} + * emits the current window and propagates the notification from the current {@code Flowable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -18022,9 +19258,9 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit) * a trade-off for ensuring upstream cancellation can happen under some race conditions. *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner. - * The returned {@code Publisher} doesn't support backpressure as it uses - * time to control the creation of windows. The returned inner {@code Publisher}s honor + *
The operator consumes the current {@code Flowable} in an unbounded manner. + * The resulting {@code Flowable} doesn't support backpressure as it uses + * time to control the creation of windows. The emitted inner {@code Flowable}s honor * backpressure and may hold up to {@code count} elements at most.
*
Scheduler:
*
This version of {@code window} operates by default on the {@code computation} {@link Scheduler}.
@@ -18037,9 +19273,9 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit) * the unit of time that applies to the {@code timespan} argument * @param count * the maximum size of each window before it should be emitted - * @return a {@code Flowable} that emits connected, non-overlapping windows of items from the source {@code Publisher} - * that were emitted during a fixed duration of time or when the window has reached maximum capacity - * (whichever occurs first) + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -18052,13 +19288,13 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping windows, each of a fixed duration as specified by the + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping windows, each of a fixed duration as specified by the * {@code timespan} argument or a maximum size as specified by the {@code count} argument (whichever is - * reached first). When the source {@code Publisher} completes or encounters an error, the resulting {@code Publisher} - * emits the current window and propagates the notification from the source {@code Publisher}. + * reached first). When the current {@code Flowable} completes or encounters an error, the resulting {@code Flowable} + * emits the current window and propagates the notification from the current {@code Flowable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -18066,9 +19302,9 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, * a trade-off for ensuring upstream cancellation can happen under some race conditions. *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner. - * The returned {@code Publisher} doesn't support backpressure as it uses - * time to control the creation of windows. The returned inner {@code Publisher}s honor + *
The operator consumes the current {@code Flowable} in an unbounded manner. + * The resulting {@code Flowable} doesn't support backpressure as it uses + * time to control the creation of windows. The emitted inner {@code Flowable}s honor * backpressure and may hold up to {@code count} elements at most.
*
Scheduler:
*
This version of {@code window} operates by default on the {@code computation} {@link Scheduler}.
@@ -18083,9 +19319,9 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, * the maximum size of each window before it should be emitted * @param restart * if {@code true}, when a window reaches the capacity limit, the timer is restarted as well - * @return a {@code Flowable} that emits connected, non-overlapping windows of items from the source {@code Publisher} - * that were emitted during a fixed duration of time or when the window has reached maximum capacity - * (whichever occurs first) + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -18098,12 +19334,12 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping windows, each of a fixed duration as specified by the - * {@code timespan} argument. When the source {@code Publisher} completes or encounters an error, the resulting - * {@code Publisher} emits the current window and propagates the notification from the source {@code Publisher}. + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping windows, each of a fixed duration as specified by the + * {@code timespan} argument. When the current {@code Flowable} completes or encounters an error, the resulting + * {@code Flowable} emits the current window and propagates the notification from the current {@code Flowable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -18111,9 +19347,9 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, * a trade-off for ensuring upstream cancellation can happen under some race conditions. *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner. - * The returned {@code Publisher} doesn't support backpressure as it uses - * time to control the creation of windows. The returned inner {@code Publisher}s honor + *
The operator consumes the current {@code Flowable} in an unbounded manner. + * The resulting {@code Flowable} doesn't support backpressure as it uses + * time to control the creation of windows. The emitted inner {@code Flowable}s honor * backpressure but have an unbounded inner buffer that may lead to {@link OutOfMemoryError} * if left unconsumed.
*
Scheduler:
@@ -18127,8 +19363,8 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, * the unit of time which applies to the {@code timespan} argument * @param scheduler * the {@code Scheduler} to use when determining the end and start of a window - * @return a {@code Flowable} that emits connected, non-overlapping windows containing items emitted by the - * source {@code Publisher} within a fixed duration + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -18141,13 +19377,13 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping windows, each of a fixed duration specified by the + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping windows, each of a fixed duration specified by the * {@code timespan} argument or a maximum size specified by the {@code count} argument (whichever is reached - * first). When the source {@code Publisher} completes or encounters an error, the resulting {@code Publisher} emits the - * current window and propagates the notification from the source {@code Publisher}. + * first). When the current {@code Flowable} completes or encounters an error, the resulting {@code Flowable} emits the + * current window and propagates the notification from the current {@code Flowable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -18155,9 +19391,9 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, * a trade-off for ensuring upstream cancellation can happen under some race conditions. *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner. - * The returned {@code Publisher} doesn't support backpressure as it uses - * time to control the creation of windows. The returned inner {@code Publisher}s honor + *
The operator consumes the current {@code Flowable} in an unbounded manner. + * The resulting {@code Flowable} doesn't support backpressure as it uses + * time to control the creation of windows. The emitted inner {@code Flowable}s honor * backpressure and may hold up to {@code count} elements at most.
*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
@@ -18172,9 +19408,9 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, * the maximum size of each window before it should be emitted * @param scheduler * the {@code Scheduler} to use when determining the end and start of a window - * @return a {@code Flowable} that emits connected, non-overlapping windows of items from the source {@code Publisher} - * that were emitted during a fixed duration of time or when the window has reached maximum capacity - * (whichever occurs first) + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -18187,13 +19423,13 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping windows, each of a fixed duration specified by the + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping windows, each of a fixed duration specified by the * {@code timespan} argument or a maximum size specified by the {@code count} argument (whichever is reached - * first). When the source {@code Publisher} completes or encounters an error, the resulting {@code Publisher} emits the - * current window and propagates the notification from the source {@code Publisher}. + * first). When the current {@code Flowable} completes or encounters an error, the resulting {@code Flowable} emits the + * current window and propagates the notification from the current {@code Flowable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -18201,9 +19437,9 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, * a trade-off for ensuring upstream cancellation can happen under some race conditions. *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner. - * The returned {@code Publisher} doesn't support backpressure as it uses - * time to control the creation of windows. The returned inner {@code Publisher}s honor + *
The operator consumes the current {@code Flowable} in an unbounded manner. + * The resulting {@code Flowable} doesn't support backpressure as it uses + * time to control the creation of windows. The emitted inner {@code Flowable}s honor * backpressure and may hold up to {@code count} elements at most.
*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
@@ -18220,9 +19456,9 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, * the {@code Scheduler} to use when determining the end and start of a window * @param restart * if {@code true}, when a window reaches the capacity limit, the timer is restarted as well - * @return a {@code Flowable} that emits connected, non-overlapping windows of items from the source {@code Publisher} - * that were emitted during a fixed duration of time or when the window has reached maximum capacity - * (whichever occurs first) + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -18235,13 +19471,13 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits connected, non-overlapping windows, each of a fixed duration specified by the + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits connected, non-overlapping windows, each of a fixed duration specified by the * {@code timespan} argument or a maximum size specified by the {@code count} argument (whichever is reached - * first). When the source {@code Publisher} completes or encounters an error, the resulting {@code Publisher} emits the - * current window and propagates the notification from the source {@code Publisher}. + * first). When the current {@code Flowable} completes or encounters an error, the resulting {@code Flowable} emits the + * current window and propagates the notification from the current {@code Flowable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -18249,9 +19485,9 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, * a trade-off for ensuring upstream cancellation can happen under some race conditions. *

*
Backpressure:
- *
The operator consumes the source {@code Publisher} in an unbounded manner. - * The returned {@code Publisher} doesn't support backpressure as it uses - * time to control the creation of windows. The returned inner {@code Publisher}s honor + *
The operator consumes the current {@code Flowable} in an unbounded manner. + * The resulting {@code Flowable} doesn't support backpressure as it uses + * time to control the creation of windows. The emitted inner {@code Flowable}s honor * backpressure and may hold up to {@code count} elements at most.
*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
@@ -18270,9 +19506,9 @@ public final Flowable> window(long timespan, @NonNull TimeUnit unit, * if {@code true}, when a window reaches the capacity limit, the timer is restarted as well * @param bufferSize * the capacity hint for the buffer in the inner windows - * @return a {@code Flowable} that emits connected, non-overlapping windows of items from the source {@code Publisher} - * that were emitted during a fixed duration of time or when the window has reached maximum capacity - * (whichever occurs first) + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code count}, {@code timespan} or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -18290,11 +19526,11 @@ public final Flowable> window( } /** - * Returns a {@code Flowable} that emits non-overlapping windows of items it collects from the source {@link Publisher} + * Returns a {@code Flowable} that emits non-overlapping windows of items it collects from the current {@code Flowable} * where the boundary of each window is determined by the items emitted from a specified boundary-governing - * {@code Publisher}. + * {@link Publisher}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -18312,25 +19548,24 @@ public final Flowable> window( * the window element type (ignored) * @param boundaryIndicator * a {@code Publisher} whose emitted items close and open windows - * @return a {@code Flowable} that emits non-overlapping windows of items it collects from the source {@code Publisher} - * where the boundary of each window is determined by the items emitted from the {@code boundary} - * {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code boundaryIndicator} is {@code null} * @see ReactiveX operators documentation: Window */ @CheckReturnValue @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable> window(@NonNull Publisher boundaryIndicator) { + public final <@NonNull B> Flowable> window(@NonNull Publisher boundaryIndicator) { return window(boundaryIndicator, bufferSize()); } /** - * Returns a {@code Flowable} that emits non-overlapping windows of items it collects from the source {@link Publisher} + * Returns a {@code Flowable} that emits non-overlapping windows of items it collects from the current {@code Flowable} * where the boundary of each window is determined by the items emitted from a specified boundary-governing - * {@code Publisher}. + * {@link Publisher}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -18350,28 +19585,28 @@ public final Flowable> window(@NonNull Publisher boundaryIndi * a {@code Publisher} whose emitted items close and open windows * @param bufferSize * the capacity hint for the buffer in the inner windows - * @return a {@code Flowable} that emits non-overlapping windows of items it collects from the source {@code Publisher} - * where the boundary of each window is determined by the items emitted from the {@code boundary} - * {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code boundaryIndicator} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable> window(@NonNull Publisher boundaryIndicator, int bufferSize) { + public final <@NonNull B> Flowable> window(@NonNull Publisher boundaryIndicator, int bufferSize) { Objects.requireNonNull(boundaryIndicator, "boundaryIndicator is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); return RxJavaPlugins.onAssembly(new FlowableWindowBoundary<>(this, boundaryIndicator, bufferSize)); } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits windows that contain those items emitted by the source {@code Publisher} between the time when - * the {@code windowOpenings} {@code Publisher} emits an item and when the {@code Publisher} returned by + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits windows that contain those items emitted by the current {@code Flowable} between the time when + * the {@code windowOpenings} {@link Publisher} emits an item and when the {@code Publisher} returned by * {@code closingSelector} emits an item. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -18394,27 +19629,27 @@ public final Flowable> window(@NonNull Publisher boundaryIndi * @param closingIndicator * a {@link Function} that produces a {@code Publisher} for every window created. When this {@code Publisher} * emits an item, the associated window is closed and emitted - * @return a {@code Flowable} that emits windows of items emitted by the source {@code Publisher} that are governed by - * the specified window-governing {@code Publisher}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code openingIndicator} or {@code closingIndicator} is {@code null} * @see ReactiveX operators documentation: Window */ @CheckReturnValue @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable> window( + public final <@NonNull U, @NonNull V> Flowable> window( @NonNull Publisher openingIndicator, - @NonNull Function> closingIndicator) { + @NonNull Function> closingIndicator) { return window(openingIndicator, closingIndicator, bufferSize()); } /** - * Returns a {@code Flowable} that emits windows of items it collects from the source {@link Publisher}. The resulting - * {@code Publisher} emits windows that contain those items emitted by the source {@code Publisher} between the time when - * the {@code windowOpenings} {@code Publisher} emits an item and when the {@code Publisher} returned by + * Returns a {@code Flowable} that emits windows of items it collects from the current {@code Flowable}. The resulting + * {@code Flowable} emits windows that contain those items emitted by the current {@code Flowable} between the time when + * the {@code windowOpenings} {@link Publisher} emits an item and when the {@code Publisher} returned by * {@code closingSelector} emits an item. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -18439,17 +19674,18 @@ public final Flowable> window( * emits an item, the associated window is closed and emitted * @param bufferSize * the capacity hint for the buffer in the inner windows - * @return a {@code Flowable} that emits windows of items emitted by the source {@code Publisher} that are governed by - * the specified window-governing {@code Publisher}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code openingIndicator} or {@code closingIndicator} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable> window( + public final <@NonNull U, @NonNull V> Flowable> window( @NonNull Publisher openingIndicator, - @NonNull Function> closingIndicator, int bufferSize) { + @NonNull Function> closingIndicator, int bufferSize) { Objects.requireNonNull(openingIndicator, "openingIndicator is null"); Objects.requireNonNull(closingIndicator, "closingIndicator is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); @@ -18457,10 +19693,17 @@ public final Flowable> window( } /** - * Merges the specified {@link Publisher} into this {@code Publisher} sequence by using the {@code resultSelector} - * function only when the source {@code Publisher} (this instance) emits an item. + * Merges the specified {@link Publisher} into the current {@code Flowable} sequence by using the {@code resultSelector} + * function only when the current {@code Flowable} (this instance) emits an item. + * + *

Note that this operator doesn't emit anything until the other source has produced at + * least one value. The resulting emission only happens when the current {@code Flowable} emits (and + * not when the other source emits, unlike combineLatest). + * If the other source doesn't produce any value and just completes, the sequence is completed immediately. + * If the upstream completes before the other source has produced at least one value, the sequence completes + * without emission. *

- * + * * *

*
Backpressure:
@@ -18476,11 +19719,10 @@ public final Flowable> window( * @param other * the other {@code Publisher} * @param combiner - * the function to call when this {@code Publisher} emits an item and the other {@code Publisher} has already - * emitted an item, to generate the item to be emitted by the resulting {@code Publisher} - * @return a {@code Flowable} that merges the specified {@code Publisher} into this {@code Publisher} by using the - * {@code resultSelector} function only when the source {@code Publisher} sequence (this instance) emits an - * item + * the function to call when the current {@code Flowable} emits an item and the other {@code Publisher} has already + * emitted an item, to generate the item to be emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} or {@code combiner} is {@code null} * @since 2.0 * @see ReactiveX operators documentation: CombineLatest */ @@ -18488,7 +19730,7 @@ public final Flowable> window( @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable withLatestFrom(@NonNull Publisher other, + public final <@NonNull U, @NonNull R> Flowable withLatestFrom(@NonNull Publisher other, @NonNull BiFunction combiner) { Objects.requireNonNull(other, "other is null"); Objects.requireNonNull(combiner, "combiner is null"); @@ -18497,17 +19739,19 @@ public final Flowable> window( } /** - * Combines the value emission from this {@link Publisher} with the latest emissions from the - * other {@code Publisher}s via a function to produce the output item. + * Combines the value emission from the current {@code Flowable} with the latest emissions from the + * other {@link Publisher}s via a function to produce the output item. * *

Note that this operator doesn't emit anything until all other sources have produced at - * least one value. The resulting emission only happens when this {@code Publisher} emits (and + * least one value. The resulting emission only happens when the current {@code Flowable} emits (and * not when any of the other sources emit, unlike combineLatest). * If a source doesn't produce any value and just completes, the sequence is completed immediately. + * If the upstream completes before all other sources have produced at least one value, the sequence completes + * without emission. * *

*
Backpressure:
- *
This operator is a pass-through for backpressure behavior between the source {@code Publisher} + *
This operator is a pass-through for backpressure behavior between the current {@code Flowable} * and the downstream {@link Subscriber}. The other {@code Publisher}s are consumed in an unbounded manner.
*
Scheduler:
*
This operator does not operate by default on a particular {@link Scheduler}.
@@ -18519,14 +19763,15 @@ public final Flowable> window( * @param source1 the first other {@code Publisher} * @param source2 the second other {@code Publisher} * @param combiner the function called with an array of values from each participating {@code Publisher} - * @return the new {@code Publisher} instance + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code combiner} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable withLatestFrom(@NonNull Publisher source1, @NonNull Publisher source2, + public final <@NonNull T1, @NonNull T2, @NonNull R> Flowable withLatestFrom(@NonNull Publisher source1, @NonNull Publisher source2, @NonNull Function3 combiner) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); @@ -18536,17 +19781,19 @@ public final Flowable> window( } /** - * Combines the value emission from this {@link Publisher} with the latest emissions from the - * other {@code Publisher}s via a function to produce the output item. + * Combines the value emission from the current {@code Flowable} with the latest emissions from the + * other {@link Publisher}s via a function to produce the output item. * *

Note that this operator doesn't emit anything until all other sources have produced at - * least one value. The resulting emission only happens when this {@code Publisher} emits (and + * least one value. The resulting emission only happens when the current {@code Flowable} emits (and * not when any of the other sources emit, unlike combineLatest). * If a source doesn't produce any value and just completes, the sequence is completed immediately. + * If the upstream completes before all other sources have produced at least one value, the sequence completes + * without emission. * *

*
Backpressure:
- *
This operator is a pass-through for backpressure behavior between the source {@code Publisher} + *
This operator is a pass-through for backpressure behavior between the current {@code Flowable} * and the downstream {@link Subscriber}. The other {@code Publisher}s are consumed in an unbounded manner.
*
Scheduler:
*
This operator does not operate by default on a particular {@link Scheduler}.
@@ -18560,14 +19807,15 @@ public final Flowable> window( * @param source2 the second other {@code Publisher} * @param source3 the third other {@code Publisher} * @param combiner the function called with an array of values from each participating {@code Publisher} - * @return the new {@code Publisher} instance + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code combiner} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable withLatestFrom( + public final <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull R> Flowable withLatestFrom( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Function4 combiner) { @@ -18580,17 +19828,19 @@ public final Flowable> window( } /** - * Combines the value emission from this {@link Publisher} with the latest emissions from the - * other {@code Publisher}s via a function to produce the output item. + * Combines the value emission from the current {@code Flowable} with the latest emissions from the + * other {@link Publisher}s via a function to produce the output item. * *

Note that this operator doesn't emit anything until all other sources have produced at - * least one value. The resulting emission only happens when this {@code Publisher} emits (and + * least one value. The resulting emission only happens when the current {@code Flowable} emits (and * not when any of the other sources emit, unlike combineLatest). * If a source doesn't produce any value and just completes, the sequence is completed immediately. + * If the upstream completes before all other sources have produced at least one value, the sequence completes + * without emission. * *

*
Backpressure:
- *
This operator is a pass-through for backpressure behavior between the source {@code Publisher} + *
This operator is a pass-through for backpressure behavior between the current {@code Flowable} * and the downstream {@link Subscriber}. The other {@code Publisher}s are consumed in an unbounded manner.
*
Scheduler:
*
This operator does not operate by default on a particular {@link Scheduler}.
@@ -18606,14 +19856,16 @@ public final Flowable> window( * @param source3 the third other {@code Publisher} * @param source4 the fourth other {@code Publisher} * @param combiner the function called with an array of values from each participating {@code Publisher} - * @return the new {@code Publisher} instance + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4} or {@code combiner} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable withLatestFrom( + public final <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull R> Flowable withLatestFrom( @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, @NonNull Publisher source4, @NonNull Function5 combiner) { @@ -18627,17 +19879,19 @@ public final Flowable> window( } /** - * Combines the value emission from this {@link Publisher} with the latest emissions from the - * other {@code Publisher}s via a function to produce the output item. + * Combines the value emission from the current {@code Flowable} with the latest emissions from the + * other {@link Publisher}s via a function to produce the output item. * *

Note that this operator doesn't emit anything until all other sources have produced at - * least one value. The resulting emission only happens when this {@code Publisher} emits (and + * least one value. The resulting emission only happens when the current {@code Flowable} emits (and * not when any of the other sources emit, unlike combineLatest). * If a source doesn't produce any value and just completes, the sequence is completed immediately. + * If the upstream completes before all other sources have produced at least one value, the sequence completes + * without emission. * *

*
Backpressure:
- *
This operator is a pass-through for backpressure behavior between the source {@code Publisher} + *
This operator is a pass-through for backpressure behavior between the current {@code Flowable} * and the downstream {@link Subscriber}. The other {@code Publisher}s are consumed in an unbounded manner.
*
Scheduler:
*
This operator does not operate by default on a particular {@link Scheduler}.
@@ -18646,31 +19900,34 @@ public final Flowable> window( * @param the result value type * @param others the array of other sources * @param combiner the function called with an array of values from each participating {@code Publisher} - * @return the new {@code Publisher} instance + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code others} or {@code combiner} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public final <@NonNull R> Flowable withLatestFrom(@NonNull Publisher[] others, @NonNull Function combiner) { + public final <@NonNull R> Flowable withLatestFrom(@NonNull Publisher<@NonNull ?>[] others, @NonNull Function combiner) { Objects.requireNonNull(others, "others is null"); Objects.requireNonNull(combiner, "combiner is null"); return RxJavaPlugins.onAssembly(new FlowableWithLatestFromMany<>(this, others, combiner)); } /** - * Combines the value emission from this {@link Publisher} with the latest emissions from the - * other {@code Publisher}s via a function to produce the output item. + * Combines the value emission from the current {@code Flowable} with the latest emissions from the + * other {@link Publisher}s via a function to produce the output item. * *

Note that this operator doesn't emit anything until all other sources have produced at - * least one value. The resulting emission only happens when this {@code Publisher} emits (and + * least one value. The resulting emission only happens when the current {@code Flowable} emits (and * not when any of the other sources emit, unlike combineLatest). * If a source doesn't produce any value and just completes, the sequence is completed immediately. + * If the upstream completes before all other sources have produced at least one value, the sequence completes + * without emission. * *

*
Backpressure:
- *
This operator is a pass-through for backpressure behavior between the source {@code Publisher} + *
This operator is a pass-through for backpressure behavior between the current {@code Flowable} * and the downstream {@link Subscriber}. The other {@code Publisher}s are consumed in an unbounded manner.
*
Scheduler:
*
This operator does not operate by default on a particular {@link Scheduler}.
@@ -18679,14 +19936,15 @@ public final Flowable> window( * @param the result value type * @param others the iterable of other sources * @param combiner the function called with an array of values from each participating {@code Publisher} - * @return the new {@code Publisher} instance + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code others} or {@code combiner} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable withLatestFrom(@NonNull Iterable> others, @NonNull Function combiner) { + public final <@NonNull R> Flowable withLatestFrom(@NonNull Iterable<@NonNull ? extends Publisher<@NonNull ?>> others, @NonNull Function combiner) { Objects.requireNonNull(others, "others is null"); Objects.requireNonNull(combiner, "combiner is null"); return RxJavaPlugins.onAssembly(new FlowableWithLatestFromMany<>(this, others, combiner)); @@ -18694,11 +19952,11 @@ public final Flowable withLatestFrom(@NonNull Iterable - * + * *

- * Note that the {@code other} {@code Iterable} is evaluated as items are observed from the source {@code Publisher}; it is + * Note that the {@code other} {@code Iterable} is evaluated as items are observed from the current {@code Flowable}; it is * not pre-consumed. This allows you to zip infinite streams on either side. *

*
Backpressure:
@@ -18712,21 +19970,21 @@ public final Flowable withLatestFrom(@NonNull Iterable * the type of items in the {@code other} {@code Iterable} * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param other * the {@code Iterable} sequence * @param zipper - * a function that combines the pairs of items from the {@code Publisher} and the {@code Iterable} to generate - * the items to be emitted by the resulting {@code Publisher} - * @return a {@code Flowable} that pairs up values from the source {@code Publisher} and the {@code other} {@code Iterable} - * sequence and emits the results of {@code zipFunction} applied to these pairs + * a function that combines the pairs of items from the current {@code Flowable} and the {@code Iterable} to generate + * the items to be emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable zipWith(@NonNull Iterable other, @NonNull BiFunction zipper) { + public final <@NonNull U, @NonNull R> Flowable zipWith(@NonNull Iterable other, @NonNull BiFunction zipper) { Objects.requireNonNull(other, "other is null"); Objects.requireNonNull(zipper, "zipper is null"); return RxJavaPlugins.onAssembly(new FlowableZipIterable<>(this, other, zipper)); @@ -18734,7 +19992,7 @@ public final Flowable zipWith(@NonNull Iterable other, @NonNull Bi /** * Returns a {@code Flowable} that emits items that are the result of applying a specified function to pairs of - * values, one each from the source {@link Publisher} and another specified {@code Publisher}. + * values, one each from the current {@code Flowable} and another specified {@link Publisher}. *

* The operator subscribes to its sources in the order they are specified and completes eagerly if * one of the sources is shorter than the rest while canceling the other sources. Therefore, it @@ -18748,7 +20006,7 @@ public final Flowable zipWith(@NonNull Iterable other, @NonNull Bi * use {@link #doOnCancel(Action)} as well or use {@code using()} to do cleanup in case of completion * or cancellation. *

- * + * *

*
Backpressure:
*
The operator expects backpressure from the sources and honors backpressure from the downstream. @@ -18761,28 +20019,28 @@ public final Flowable zipWith(@NonNull Iterable other, @NonNull Bi * @param * the type of items emitted by the {@code other} {@code Publisher} * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param other * the other {@code Publisher} * @param zipper * a function that combines the pairs of items from the two {@code Publisher}s to generate the items to - * be emitted by the resulting {@code Publisher} - * @return a {@code Flowable} that pairs up values from the source {@code Publisher} and the {@code other} {@code Publisher} - * and emits the results of {@code zipFunction} applied to these pairs + * be emitted by the resulting {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable zipWith(@NonNull Publisher other, @NonNull BiFunction zipper) { + public final <@NonNull U, @NonNull R> Flowable zipWith(@NonNull Publisher other, @NonNull BiFunction zipper) { Objects.requireNonNull(other, "other is null"); return zip(this, other, zipper); } /** * Returns a {@code Flowable} that emits items that are the result of applying a specified function to pairs of - * values, one each from the source {@link Publisher} and another specified {@code Publisher}. + * values, one each from the current {@code Flowable} and another specified {@link Publisher}. *

* The operator subscribes to its sources in the order they are specified and completes eagerly if * one of the sources is shorter than the rest while canceling the other sources. Therefore, it @@ -18796,7 +20054,7 @@ public final Flowable zipWith(@NonNull Publisher other, @ * use {@link #doOnCancel(Action)} as well or use {@code using()} to do cleanup in case of completion * or cancellation. *

- * + * *

*
Backpressure:
*
The operator expects backpressure from the sources and honors backpressure from the downstream. @@ -18809,16 +20067,16 @@ public final Flowable zipWith(@NonNull Publisher other, @ * @param * the type of items emitted by the {@code other} {@code Publisher} * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param other * the other {@code Publisher} * @param zipper * a function that combines the pairs of items from the two {@code Publisher}s to generate the items to - * be emitted by the resulting {@code Publisher} + * be emitted by the resulting {@code Flowable} * @param delayError * if {@code true}, errors from the current {@code Flowable} or the other {@code Publisher} is delayed until both terminate - * @return a {@code Flowable} that pairs up values from the source {@code Publisher} and the {@code other} {@code Publisher} - * and emits the results of {@code zipFunction} applied to these pairs + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip * @since 2.0 */ @@ -18826,14 +20084,14 @@ public final Flowable zipWith(@NonNull Publisher other, @ @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable zipWith(@NonNull Publisher other, + public final <@NonNull U, @NonNull R> Flowable zipWith(@NonNull Publisher other, @NonNull BiFunction zipper, boolean delayError) { return zip(this, other, zipper, delayError); } /** * Returns a {@code Flowable} that emits items that are the result of applying a specified function to pairs of - * values, one each from the source {@link Publisher} and another specified {@code Publisher}. + * values, one each from the current {@code Flowable} and another specified {@link Publisher}. *

* The operator subscribes to its sources in the order they are specified and completes eagerly if * one of the sources is shorter than the rest while canceling the other sources. Therefore, it @@ -18847,7 +20105,7 @@ public final Flowable zipWith(@NonNull Publisher other, * use {@link #doOnCancel(Action)} as well or use {@code using()} to do cleanup in case of completion * or cancellation. *

- * + * *

*
Backpressure:
*
The operator expects backpressure from the sources and honors backpressure from the downstream. @@ -18860,18 +20118,19 @@ public final Flowable zipWith(@NonNull Publisher other, * @param * the type of items emitted by the {@code other} {@code Publisher} * @param - * the type of items emitted by the resulting {@code Publisher} + * the type of items emitted by the resulting {@code Flowable} * @param other * the other {@code Publisher} * @param zipper * a function that combines the pairs of items from the two {@code Publisher}s to generate the items to - * be emitted by the resulting {@code Publisher} + * be emitted by the resulting {@code Flowable} * @param bufferSize * the capacity hint for the buffer in the inner windows * @param delayError * if {@code true}, errors from the current {@code Flowable} or the other {@code Publisher} is delayed until both terminate - * @return a {@code Flowable} that pairs up values from the source {@code Publisher} and the {@code other} {@code Publisher} - * and emits the results of {@code zipFunction} applied to these pairs + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} or {@code zipper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Zip * @since 2.0 */ @@ -18879,7 +20138,7 @@ public final Flowable zipWith(@NonNull Publisher other, @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable zipWith(@NonNull Publisher other, + public final <@NonNull U, @NonNull R> Flowable zipWith(@NonNull Publisher other, @NonNull BiFunction zipper, boolean delayError, int bufferSize) { return zip(this, other, zipper, delayError, bufferSize); } @@ -18985,6 +20244,7 @@ public final TestSubscriber test(long initialRequest, boolean cancel) { // No * @param the element type of the optional value * @param optional the optional value to convert into a {@code Flowable} * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code optional} is {@code null} * @since 3.0.0 * @see #just(Object) * @see #empty() @@ -18993,7 +20253,7 @@ public final TestSubscriber test(long initialRequest, boolean cancel) { // No @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable<@NonNull T> fromOptional(@NonNull Optional optional) { + public static <@NonNull T> Flowable<@NonNull T> fromOptional(@NonNull Optional optional) { Objects.requireNonNull(optional, "optional is null"); return optional.map(Flowable::just).orElseGet(Flowable::empty); } @@ -19004,7 +20264,7 @@ public final TestSubscriber test(long initialRequest, boolean cancel) { // No * *

* Note that the operator takes an already instantiated, running or terminated {@code CompletionStage}. - * If the optional is to be created per consumer upon subscription, use {@link #defer(Supplier)} + * If the {@code CompletionStage} is to be created per consumer upon subscription, use {@link #defer(Supplier)} * around {@code fromCompletionStage}: *


      * Flowable.defer(() -> Flowable.fromCompletionStage(createCompletionStage()));
@@ -19024,13 +20284,14 @@ public final TestSubscriber test(long initialRequest, boolean cancel) { // No
      * @param  the element type of the {@code CompletionStage}
      * @param stage the {@code CompletionStage} to convert to {@code Flowable} and signal its terminal value or error
      * @return the new {@code Flowable} instance
+     * @throws NullPointerException if {@code stage} is {@code null}
      * @since 3.0.0
      */
     @CheckReturnValue
     @BackpressureSupport(BackpressureKind.FULL)
     @SchedulerSupport(SchedulerSupport.NONE)
     @NonNull
-    public static  Flowable<@NonNull T> fromCompletionStage(@NonNull CompletionStage stage) {
+    public static <@NonNull T> Flowable<@NonNull T> fromCompletionStage(@NonNull CompletionStage stage) {
         Objects.requireNonNull(stage, "stage is null");
         return RxJavaPlugins.onAssembly(new FlowableFromCompletionStage<>(stage));
     }
@@ -19069,6 +20330,7 @@ public final TestSubscriber test(long initialRequest, boolean cancel) { // No
      * @param  the element type of the source {@code Stream}
      * @param stream the {@code Stream} of values to emit
      * @return the new {@code Flowable} instance
+     * @throws NullPointerException if {@code stream} is {@code null}
      * @since 3.0.0
      * @see #fromIterable(Iterable)
      */
@@ -19076,7 +20338,7 @@ public final TestSubscriber test(long initialRequest, boolean cancel) { // No
     @BackpressureSupport(BackpressureKind.FULL)
     @SchedulerSupport(SchedulerSupport.NONE)
     @NonNull
-    public static  Flowable<@NonNull T> fromStream(@NonNull Stream stream) {
+    public static <@NonNull T> Flowable<@NonNull T> fromStream(@NonNull Stream stream) {
         Objects.requireNonNull(stream, "stream is null");
         return RxJavaPlugins.onAssembly(new FlowableFromStream<>(stream));
     }
@@ -19097,6 +20359,7 @@ public final TestSubscriber test(long initialRequest, boolean cancel) { // No
      * @param mapper the function that receives the upstream item and should return a non-empty {@code Optional}
      * to emit as the output or an empty {@code Optional} to skip to the next upstream value
      * @return the new {@code Flowable} instance
+     * @throws NullPointerException if {@code mapper} is {@code null}
      * @since 3.0.0
      * @see #map(Function)
      * @see #filter(Predicate)
@@ -19127,6 +20390,7 @@ public final TestSubscriber test(long initialRequest, boolean cancel) { // No
      * @param collector the interface defining the container supplier, accumulator and finisher functions;
      * see {@link Collectors} for some standard implementations
      * @return the new {@link Single} instance
+     * @throws NullPointerException if {@code collector} is {@code null}
      * @since 3.0.0
      * @see Collectors
      * @see #collect(Supplier, BiConsumer)
@@ -19135,7 +20399,7 @@ public final TestSubscriber test(long initialRequest, boolean cancel) { // No
     @BackpressureSupport(BackpressureKind.UNBOUNDED_IN)
     @SchedulerSupport(SchedulerSupport.NONE)
     @NonNull
-    public final <@NonNull R, A> Single collect(@NonNull Collector collector) {
+    public final <@NonNull R, @Nullable A> Single collect(@NonNull Collector collector) {
         Objects.requireNonNull(collector, "collector is null");
         return RxJavaPlugins.onAssembly(new FlowableCollectWithCollectorSingle<>(this, collector));
     }
@@ -19253,7 +20517,7 @@ public final CompletionStage lastStage(@Nullable T defaultItem) {
      * Signals the first upstream item or a {@link NoSuchElementException} if the upstream is empty via
      * a {@link CompletionStage}.
      * 

- * + * *

* The upstream can be canceled by converting the resulting {@code CompletionStage} into * {@link CompletableFuture} via {@link CompletionStage#toCompletableFuture()} and @@ -19398,6 +20662,7 @@ public final Stream blockingStream() { * @param prefetch the number of items to request from the upstream to limit the number of * in-flight items and item generation. * @return the new {@code Stream} instance + * @throws IllegalArgumentException if {@code prefetch} is non-positive * @since 3.0.0 */ @CheckReturnValue @@ -19450,6 +20715,7 @@ public final Stream blockingStream(int prefetch) { * @param mapper the function that receives an upstream item and should return a {@code Stream} whose elements * will be emitted to the downstream * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @since 3.0.0 * @see #concatMap(Function) * @see #concatMapIterable(Function) @@ -19503,6 +20769,8 @@ public final Stream blockingStream(int prefetch) { * will be emitted to the downstream * @param prefetch the number of upstream items to request upfront, then 75% of this amount after each 75% upstream items received * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive * @since 3.0.0 * @see #concatMap(Function, int) * @see #concatMapIterable(Function, int) @@ -19558,6 +20826,7 @@ public final Stream blockingStream(int prefetch) { * @param mapper the function that receives an upstream item and should return a {@code Stream} whose elements * will be emitted to the downstream * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @since 3.0.0 * @see #flatMap(Function) * @see #flatMapIterable(Function) @@ -19611,6 +20880,8 @@ public final Stream blockingStream(int prefetch) { * will be emitted to the downstream * @param prefetch the number of upstream items to request upfront, then 75% of this amount after each 75% upstream items received * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive * @since 3.0.0 * @see #flatMap(Function, int) * @see #flatMapIterable(Function, int) diff --git a/src/main/java/io/reactivex/rxjava3/core/FlowableConverter.java b/src/main/java/io/reactivex/rxjava3/core/FlowableConverter.java index 92733c3c1e5..1db19b9144f 100644 --- a/src/main/java/io/reactivex/rxjava3/core/FlowableConverter.java +++ b/src/main/java/io/reactivex/rxjava3/core/FlowableConverter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,13 +24,12 @@ * @since 2.2 */ @FunctionalInterface -public interface FlowableConverter { +public interface FlowableConverter<@NonNull T, @NonNull R> { /** * Applies a function to the upstream {@link Flowable} and returns a converted value of type {@code R}. * * @param upstream the upstream {@code Flowable} instance * @return the converted value */ - @NonNull R apply(@NonNull Flowable upstream); } diff --git a/src/main/java/io/reactivex/rxjava3/core/FlowableEmitter.java b/src/main/java/io/reactivex/rxjava3/core/FlowableEmitter.java index 1221721f295..5ad6850389b 100644 --- a/src/main/java/io/reactivex/rxjava3/core/FlowableEmitter.java +++ b/src/main/java/io/reactivex/rxjava3/core/FlowableEmitter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,7 +15,7 @@ import io.reactivex.rxjava3.annotations.*; import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.functions.Cancellable; +import io.reactivex.rxjava3.functions.*; /** * Abstraction over a Reactive Streams {@link org.reactivestreams.Subscriber} that allows associating @@ -48,7 +48,7 @@ * * @param the value type to emit */ -public interface FlowableEmitter extends Emitter { +public interface FlowableEmitter<@NonNull T> extends Emitter { /** * Sets a Disposable on this emitter; any previous {@link Disposable} diff --git a/src/main/java/io/reactivex/rxjava3/core/FlowableOnSubscribe.java b/src/main/java/io/reactivex/rxjava3/core/FlowableOnSubscribe.java index 156b9f2dc71..6c5263b779c 100644 --- a/src/main/java/io/reactivex/rxjava3/core/FlowableOnSubscribe.java +++ b/src/main/java/io/reactivex/rxjava3/core/FlowableOnSubscribe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,19 +10,20 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.core; import io.reactivex.rxjava3.annotations.NonNull; /** * A functional interface that has a {@code subscribe()} method that receives - * an instance of a {@link FlowableEmitter} instance that allows pushing + * a {@link FlowableEmitter} instance that allows pushing * events in a backpressure-safe and cancellation-safe manner. * * @param the value type pushed */ @FunctionalInterface -public interface FlowableOnSubscribe { +public interface FlowableOnSubscribe<@NonNull T> { /** * Called for each {@link org.reactivestreams.Subscriber Subscriber} that subscribes. diff --git a/src/main/java/io/reactivex/rxjava3/core/FlowableOperator.java b/src/main/java/io/reactivex/rxjava3/core/FlowableOperator.java index 5b5855ea2fd..aa2d5ff0e7c 100644 --- a/src/main/java/io/reactivex/rxjava3/core/FlowableOperator.java +++ b/src/main/java/io/reactivex/rxjava3/core/FlowableOperator.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,7 +24,7 @@ * @param the value type of the upstream */ @FunctionalInterface -public interface FlowableOperator { +public interface FlowableOperator<@NonNull Downstream, @NonNull Upstream> { /** * Applies a function to the child {@link Subscriber} and returns a new parent {@code Subscriber}. * @param subscriber the child {@code Subscriber} instance diff --git a/src/main/java/io/reactivex/rxjava3/core/FlowableSubscriber.java b/src/main/java/io/reactivex/rxjava3/core/FlowableSubscriber.java index 23449fbedc0..f97eadbd37b 100644 --- a/src/main/java/io/reactivex/rxjava3/core/FlowableSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/core/FlowableSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,14 +18,16 @@ import io.reactivex.rxjava3.annotations.NonNull; /** - * Represents a Reactive-Streams inspired {@link Subscriber} that is RxJava 2 only - * and weakens rules §1.3 and §3.9 of the specification for gaining performance. + * Represents a Reactive-Streams inspired {@link Subscriber} that is RxJava 3 only + * and weakens the Reactive Streams rules §1.3 + * and §3.9 of the specification + * for gaining performance. * *

History: 2.0.7 - experimental; 2.1 - beta * @param the value type * @since 2.2 */ -public interface FlowableSubscriber extends Subscriber { +public interface FlowableSubscriber<@NonNull T> extends Subscriber { /** * Implementors of this method should make sure everything that needs diff --git a/src/main/java/io/reactivex/rxjava3/core/FlowableTransformer.java b/src/main/java/io/reactivex/rxjava3/core/FlowableTransformer.java index 3b98a97dad3..fe51a2d5d7e 100644 --- a/src/main/java/io/reactivex/rxjava3/core/FlowableTransformer.java +++ b/src/main/java/io/reactivex/rxjava3/core/FlowableTransformer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,7 +24,7 @@ * @param the downstream value type */ @FunctionalInterface -public interface FlowableTransformer { +public interface FlowableTransformer<@NonNull Upstream, @NonNull Downstream> { /** * Applies a function to the upstream {@link Flowable} and returns a {@link Publisher} with * optionally different element type. diff --git a/src/main/java/io/reactivex/rxjava3/core/Maybe.java b/src/main/java/io/reactivex/rxjava3/core/Maybe.java index 84a088d5c7e..8ae4137c839 100644 --- a/src/main/java/io/reactivex/rxjava3/core/Maybe.java +++ b/src/main/java/io/reactivex/rxjava3/core/Maybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,20 +20,21 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.annotations.*; -import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.*; import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.jdk8.*; -import io.reactivex.rxjava3.internal.observers.BlockingMultiObserver; +import io.reactivex.rxjava3.internal.observers.*; import io.reactivex.rxjava3.internal.operators.flowable.*; import io.reactivex.rxjava3.internal.operators.maybe.*; import io.reactivex.rxjava3.internal.operators.mixed.*; +import io.reactivex.rxjava3.internal.operators.observable.ObservableElementAtMaybe; import io.reactivex.rxjava3.internal.util.ErrorMode; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.schedulers.*; /** * The {@code Maybe} class represents a deferred computation and emission of a single value, no value at all or an exception. @@ -46,10 +47,10 @@ * onSubscribe (onSuccess | onError | onComplete)? *

*

- * Note that {@code onSuccess}, {@code onError} and {@code onComplete} are mutually exclusive events; unlike {@code Observable}, + * Note that {@code onSuccess}, {@code onError} and {@code onComplete} are mutually exclusive events; unlike {@link Observable}, * {@code onSuccess} is never followed by {@code onError} or {@code onComplete}. *

- * Like {@link Observable}, a running {@code Maybe} can be stopped through the {@link Disposable} instance + * Like {@code Observable}, a running {@code Maybe} can be stopped through the {@link Disposable} instance * provided to consumers through {@link MaybeObserver#onSubscribe}. *

* Like an {@code Observable}, a {@code Maybe} is lazy, can be either "hot" or "cold", synchronous or @@ -61,7 +62,7 @@ *

* *

- * See {@link Flowable} or {@link Observable} for the + * See {@link Flowable} or {@code Observable} for the * implementation of the Reactive Pattern for a stream or vector of values. *

* Example: @@ -109,32 +110,33 @@ * @since 2.0 * @see io.reactivex.rxjava3.observers.DisposableMaybeObserver */ -public abstract class Maybe implements MaybeSource { +public abstract class Maybe<@NonNull T> implements MaybeSource { /** - * Runs multiple MaybeSources and signals the events of the first one that signals (disposing - * the rest). + * Runs multiple {@link MaybeSource}s provided by an {@link Iterable} sequence and + * signals the events of the first one that signals (disposing the rest). *

- * + * *

*
Scheduler:
*
{@code amb} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources the Iterable sequence of sources. A subscription to each source will - * occur in the same order as in the Iterable. - * @return the new Maybe instance + * @param sources the {@code Iterable} sequence of sources. A subscription to each source will + * occur in the same order as in the {@code Iterable}. + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code sources} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe amb(@NonNull Iterable> sources) { + public static <@NonNull T> Maybe amb(@NonNull Iterable<@NonNull ? extends MaybeSource> sources) { Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new MaybeAmb<>(null, sources)); } /** - * Runs multiple MaybeSources and signals the events of the first one that signals (disposing + * Runs multiple {@link MaybeSource}s and signals the events of the first one that signals (disposing * the rest). *

* @@ -145,13 +147,15 @@ public static Maybe amb(@NonNull Iterable the value type * @param sources the array of sources. A subscription to each source will * occur in the same order as in the array. - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code sources} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull @SafeVarargs - public static Maybe ambArray(@NonNull MaybeSource... sources) { + public static <@NonNull T> Maybe ambArray(@NonNull MaybeSource... sources) { + Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { return empty(); } @@ -164,8 +168,8 @@ public static Maybe ambArray(@NonNull MaybeSource... sources } /** - * Concatenate the single values, in a non-overlapping fashion, of the MaybeSource sources provided by - * an Iterable sequence. + * Concatenate the single values, in a non-overlapping fashion, of the {@link MaybeSource} sources provided by + * an {@link Iterable} sequence as a {@link Flowable} sequence. *

* *

@@ -175,22 +179,23 @@ public static Maybe ambArray(@NonNull MaybeSource... sources *
{@code concat} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources the Iterable sequence of MaybeSource instances - * @return the new Flowable instance + * @param sources the {@code Iterable} sequence of {@code MaybeSource} instances + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concat(@NonNull Iterable> sources) { + public static <@NonNull T> Flowable concat(@NonNull Iterable<@NonNull ? extends MaybeSource> sources) { Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new MaybeConcatIterable<>(sources)); } /** - * Returns a Flowable that emits the items emitted by two MaybeSources, one after the other. + * Returns a {@link Flowable} that emits the items emitted by two {@link MaybeSource}s, one after the other. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer.
@@ -200,26 +205,27 @@ public static Flowable concat(@NonNull Iterable the common value type * @param source1 - * a MaybeSource to be concatenated + * a {@code MaybeSource} to be concatenated * @param source2 - * a MaybeSource to be concatenated - * @return a Flowable that emits items emitted by the two source MaybeSources, one after the other. + * a {@code MaybeSource} to be concatenated + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @see ReactiveX operators documentation: Concat */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concat(@NonNull MaybeSource source1, @NonNull MaybeSource source2) { + public static <@NonNull T> Flowable concat(@NonNull MaybeSource source1, @NonNull MaybeSource source2) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); return concatArray(source1, source2); } /** - * Returns a Flowable that emits the items emitted by three MaybeSources, one after the other. + * Returns a {@link Flowable} that emits the items emitted by three {@link MaybeSource}s, one after the other. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer.
@@ -229,19 +235,20 @@ public static Flowable concat(@NonNull MaybeSource source1, * * @param the common value type * @param source1 - * a MaybeSource to be concatenated + * a {@code MaybeSource} to be concatenated * @param source2 - * a MaybeSource to be concatenated + * a {@code MaybeSource} to be concatenated * @param source3 - * a MaybeSource to be concatenated - * @return a Flowable that emits items emitted by the three source MaybeSources, one after the other. + * a {@code MaybeSource} to be concatenated + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} * @see ReactiveX operators documentation: Concat */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concat( + public static <@NonNull T> Flowable concat( @NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull MaybeSource source3) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); @@ -250,9 +257,9 @@ public static Flowable concat( } /** - * Returns a Flowable that emits the items emitted by four MaybeSources, one after the other. + * Returns a {@link Flowable} that emits the items emitted by four {@link MaybeSource}s, one after the other. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer.
@@ -262,21 +269,22 @@ public static Flowable concat( * * @param the common value type * @param source1 - * a MaybeSource to be concatenated + * a {@code MaybeSource} to be concatenated * @param source2 - * a MaybeSource to be concatenated + * a {@code MaybeSource} to be concatenated * @param source3 - * a MaybeSource to be concatenated + * a {@code MaybeSource} to be concatenated * @param source4 - * a MaybeSource to be concatenated - * @return a Flowable that emits items emitted by the four source MaybeSources, one after the other. + * a {@code MaybeSource} to be concatenated + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} * @see ReactiveX operators documentation: Concat */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concat( + public static <@NonNull T> Flowable concat( @NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull MaybeSource source3, @NonNull MaybeSource source4) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); @@ -286,61 +294,64 @@ public static Flowable concat( } /** - * Concatenate the single values, in a non-overlapping fashion, of the MaybeSource sources provided by - * a Publisher sequence. + * Concatenate the single values, in a non-overlapping fashion, of the {@link MaybeSource} sources provided by + * a {@link Publisher} sequence as a {@link Flowable} sequence. *

* *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer and * expects the {@code Publisher} to honor backpressure as well. If the sources {@code Publisher} - * violates this, a {@link io.reactivex.rxjava3.exceptions.MissingBackpressureException} is signalled.
+ * violates this, a {@link io.reactivex.rxjava3.exceptions.MissingBackpressureException} is signaled.
*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources the Publisher of MaybeSource instances - * @return the new Flowable instance + * @param sources the {@code Publisher} of {@code MaybeSource} instances + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable concat(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable concat(@NonNull Publisher<@NonNull ? extends MaybeSource> sources) { return concat(sources, 2); } /** - * Concatenate the single values, in a non-overlapping fashion, of the MaybeSource sources provided by - * a Publisher sequence. + * Concatenate the single values, in a non-overlapping fashion, of the {@link MaybeSource} sources provided by + * a {@link Publisher} sequence as a {@link Flowable} sequence. *

* *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer and * expects the {@code Publisher} to honor backpressure as well. If the sources {@code Publisher} - * violates this, a {@link io.reactivex.rxjava3.exceptions.MissingBackpressureException} is signalled.
+ * violates this, a {@link io.reactivex.rxjava3.exceptions.MissingBackpressureException} is signaled.
*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources the Publisher of MaybeSource instances - * @param prefetch the number of MaybeSources to prefetch from the Publisher - * @return the new Flowable instance + * @param sources the {@code Publisher} of {@code MaybeSource} instances + * @param prefetch the number of {@code MaybeSource}s to prefetch from the {@code Publisher} + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive + * @return the new {@code Flowable} instance */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Flowable concat(@NonNull Publisher> sources, int prefetch) { + public static <@NonNull T> Flowable concat(@NonNull Publisher<@NonNull ? extends MaybeSource> sources, int prefetch) { Objects.requireNonNull(sources, "sources is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new FlowableConcatMapPublisher(sources, MaybeToPublisher.instance(), prefetch, ErrorMode.IMMEDIATE)); + return RxJavaPlugins.onAssembly(new FlowableConcatMapMaybePublisher<>(sources, Functions.identity(), ErrorMode.IMMEDIATE, prefetch)); } /** - * Concatenate the single values, in a non-overlapping fashion, of the MaybeSource sources in the array. + * Concatenate the single values, in a non-overlapping fashion, of the {@link MaybeSource} sources in the array + * as a {@link Flowable} sequence. *

* *

@@ -350,15 +361,16 @@ public static Flowable concat(@NonNull Publisher{@code concatArray} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources the array of MaybeSource instances - * @return the new Flowable instance + * @param sources the array of {@code MaybeSource} instances + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs - public static Flowable concatArray(@NonNull MaybeSource... sources) { + public static <@NonNull T> Flowable concatArray(@NonNull MaybeSource... sources) { Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { return Flowable.empty(); @@ -372,8 +384,8 @@ public static Flowable concatArray(@NonNull MaybeSource... s } /** - * Concatenates a variable number of MaybeSource sources and delays errors from any of them - * till all terminate. + * Concatenates a variable number of {@link MaybeSource} sources and delays errors from any of them + * till all terminate as a {@link Flowable} sequence. *

* *

@@ -384,15 +396,16 @@ public static Flowable concatArray(@NonNull MaybeSource... s *
* @param sources the array of sources * @param the common base value type - * @return the new Flowable instance - * @throws NullPointerException if sources is null + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs @NonNull - public static Flowable concatArrayDelayError(@NonNull MaybeSource... sources) { + public static <@NonNull T> Flowable concatArrayDelayError(@NonNull MaybeSource... sources) { + Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { return Flowable.empty(); } else @@ -405,13 +418,13 @@ public static Flowable concatArrayDelayError(@NonNull MaybeSource - * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source MaybeSources. The operator buffers the value emitted by these MaybeSources and then drains them + * Eager concatenation means that once an observer subscribes, this operator subscribes to all of the + * source {@code MaybeSource}s. The operator buffers the value emitted by these {@code MaybeSource}s and then drains them * in order, each one after the previous one completes. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream.
@@ -419,8 +432,9 @@ public static Flowable concatArrayDelayError(@NonNull MaybeSourceThis method does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources a sequence of MaybeSources that need to be eagerly concatenated - * @return the new Flowable instance with the specified concatenation behavior + * @param sources a sequence of {@code MaybeSource}s that need to be eagerly concatenated + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} */ @SuppressWarnings({ "rawtypes", "unchecked" }) @BackpressureSupport(BackpressureKind.FULL) @@ -428,15 +442,45 @@ public static Flowable concatArrayDelayError(@NonNull MaybeSource Flowable concatArrayEager(@NonNull MaybeSource... sources) { + public static <@NonNull T> Flowable concatArrayEager(@NonNull MaybeSource... sources) { return Flowable.fromArray(sources).concatMapEager((Function)MaybeToPublisher.instance()); } + /** + * Concatenates a sequence of {@link MaybeSource} eagerly into a {@link Flowable} sequence. + *

+ * Eager concatenation means that once an observer subscribes, this operator subscribes to all of the + * source {@code MaybeSource}s. The operator buffers the value emitted by these {@code MaybeSource}s and then drains them + * in order, each one after the previous one completes. + *

+ * + *

+ *
Backpressure:
+ *
The operator honors backpressure from downstream.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code MaybeSource}s that need to be eagerly concatenated + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + @SafeVarargs + public static <@NonNull T> Flowable concatArrayEagerDelayError(@NonNull MaybeSource... sources) { + return Flowable.fromArray(sources).concatMapEagerDelayError((Function)MaybeToPublisher.instance(), true); + } /** - * Concatenates the Iterable sequence of MaybeSources into a single sequence by subscribing to each MaybeSource, - * one after the other, one at a time and delays any errors till the all inner MaybeSources terminate. + * Concatenates the {@link Iterable} sequence of {@link MaybeSource}s into a single sequence by subscribing to each {@code MaybeSource}, + * one after the other, one at a time and delays any errors till the all inner {@code MaybeSource}s terminate + * as a {@link Flowable} sequence. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream.
@@ -445,22 +489,22 @@ public static Flowable concatArrayEager(@NonNull MaybeSource *
* * @param the common element base type - * @param sources the Iterable sequence of MaybeSources - * @return the new Flowable with the concatenating behavior + * @param sources the {@code Iterable} sequence of {@code MaybeSource}s + * @return the new {@code Flowable} with the concatenating behavior + * @throws NullPointerException if {@code sources} is {@code null} */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concatDelayError(@NonNull Iterable> sources) { - Objects.requireNonNull(sources, "sources is null"); - return Flowable.fromIterable(sources).concatMapDelayError((Function)MaybeToPublisher.instance()); + public static <@NonNull T> Flowable concatDelayError(@NonNull Iterable<@NonNull ? extends MaybeSource> sources) { + return Flowable.fromIterable(sources).concatMapMaybeDelayError(Functions.identity()); } /** - * Concatenates the Publisher sequence of Publishers into a single sequence by subscribing to each inner Publisher, - * one after the other, one at a time and delays any errors till the all inner and the outer Publishers terminate. + * Concatenates the {@link Publisher} sequence of {@link MaybeSource}s into a single sequence by subscribing to each inner {@code MaybeSource}, + * one after the other, one at a time and delays any errors till the all inner and the outer {@code Publisher} terminate + * as a {@link Flowable} sequence. *

* *

@@ -471,26 +515,86 @@ public static Flowable concatDelayError(@NonNull Iterable * * @param the common element base type - * @param sources the Publisher sequence of Publishers - * @return the new Publisher with the concatenating behavior + * @param sources the {@code Publisher} sequence of {@code MaybeSource}s + * @return the new {@code Flowable} with the concatenating behavior + * @throws NullPointerException if {@code sources} is {@code null} + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Flowable concatDelayError(@NonNull Publisher<@NonNull ? extends MaybeSource> sources) { + return Flowable.fromPublisher(sources).concatMapMaybeDelayError(Functions.identity()); + } + /** + * Concatenates the {@link Publisher} sequence of {@link MaybeSource}s into a single sequence by subscribing to each inner {@code MaybeSource}, + * one after the other, one at a time and delays any errors till the all inner and the outer {@code Publisher} terminate + * as a {@link Flowable} sequence. + *

+ * + *

+ *
Backpressure:
+ *
{@code concatDelayError} fully supports backpressure.
+ *
Scheduler:
+ *
{@code concatDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param the common element base type + * @param sources the {@code Publisher} sequence of {@code MaybeSource}s + * @param prefetch The number of upstream items to prefetch so that fresh items are + * ready to be mapped when a previous {@code MaybeSource} terminates. + * The operator replenishes after half of the prefetch amount has been consumed + * and turned into {@code MaybeSource}s. + * @return the new {@code Flowable} with the concatenating behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive + * @since 3.0.0 */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable concatDelayError(@NonNull Publisher> sources) { - return Flowable.fromPublisher(sources).concatMapDelayError((Function)MaybeToPublisher.instance()); + public static <@NonNull T> Flowable concatDelayError(@NonNull Publisher<@NonNull ? extends MaybeSource> sources, int prefetch) { + return Flowable.fromPublisher(sources).concatMapMaybeDelayError(Functions.identity(), true, prefetch); } /** - * Concatenates a sequence of MaybeSources eagerly into a single stream of values. + * Concatenates a sequence of {@link MaybeSource}s eagerly into a {@link Flowable} sequence. *

- * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source MaybeSources. The operator buffers the values emitted by these MaybeSources and then drains them + * + *

+ * Eager concatenation means that once an observer subscribes, this operator subscribes to all of the + * source {@code MaybeSource}s. The operator buffers the values emitted by these {@code MaybeSource}s and then drains them * in order, each one after the previous one completes. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code MaybeSource} that need to be eagerly concatenated + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Flowable concatEager(@NonNull Iterable<@NonNull ? extends MaybeSource> sources) { + return Flowable.fromIterable(sources).concatMapEagerDelayError((Function)MaybeToPublisher.instance(), false); + } + + /** + * Concatenates a sequence of {@link MaybeSource}s eagerly into a {@link Flowable} sequence and + * runs a limited number of the inner sequences at once. *

- * + * + *

+ * Eager concatenation means that once an observer subscribes, this operator subscribes to all of the + * source {@code MaybeSource}s. The operator buffers the values emitted by these {@code MaybeSource}s and then drains them + * in order, each one after the previous one completes. *

*
Backpressure:
*
Backpressure is honored towards the downstream.
@@ -498,49 +602,224 @@ public static Flowable concatDelayError(@NonNull PublisherThis method does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources a sequence of MaybeSource that need to be eagerly concatenated - * @return the new Flowable instance with the specified concatenation behavior + * @param sources a sequence of {@code MaybeSource} that need to be eagerly concatenated + * @param maxConcurrency the maximum number of concurrently running inner {@code MaybeSource}s; {@link Integer#MAX_VALUE} + * is interpreted as all inner {@code MaybeSource}s can be active at the same time + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive + * @since 3.0.0 */ @SuppressWarnings({ "rawtypes", "unchecked" }) @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable concatEager(@NonNull Iterable> sources) { - return Flowable.fromIterable(sources).concatMapEager((Function)MaybeToPublisher.instance()); + public static <@NonNull T> Flowable concatEager(@NonNull Iterable<@NonNull ? extends MaybeSource> sources, int maxConcurrency) { + return Flowable.fromIterable(sources).concatMapEagerDelayError((Function)MaybeToPublisher.instance(), false, maxConcurrency, 1); } /** - * Concatenates a Publisher sequence of MaybeSources eagerly into a single stream of values. + * Concatenates a {@link Publisher} sequence of {@link MaybeSource}s eagerly into a {@link Flowable} sequence. *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * emitted source Publishers as they are observed. The operator buffers the values emitted by these - * Publishers and then drains them in order, each one after the previous one completes. + * emitted source {@code MaybeSource}s as they are observed. The operator buffers the values emitted by these + * {@code MaybeSource}s and then drains them in order, each one after the previous one completes. *

* *

*
Backpressure:
- *
Backpressure is honored towards the downstream and the outer Publisher is + *
Backpressure is honored towards the downstream and the outer {@code Publisher} is * expected to support backpressure. Violating this assumption, the operator will * signal {@link io.reactivex.rxjava3.exceptions.MissingBackpressureException}.
*
Scheduler:
*
This method does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources a sequence of Publishers that need to be eagerly concatenated - * @return the new Publisher instance with the specified concatenation behavior + * @param sources a sequence of {@code MaybeSource}s that need to be eagerly concatenated + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} */ @SuppressWarnings({ "rawtypes", "unchecked" }) @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable concatEager(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable concatEager(@NonNull Publisher<@NonNull ? extends MaybeSource> sources) { return Flowable.fromPublisher(sources).concatMapEager((Function)MaybeToPublisher.instance()); } /** - * Provides an API (via a cold Maybe) that bridges the reactive world with the callback-style world. + * Concatenates a {@link Publisher} sequence of {@link MaybeSource}s eagerly into a {@link Flowable} sequence, + * running at most the given number of inner {@code MaybeSource}s at once. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * emitted source {@code MaybeSource}s as they are observed. The operator buffers the values emitted by these + * {@code MaybeSource}s and then drains them in order, each one after the previous one completes. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream and the outer {@code Publisher} is + * expected to support backpressure. Violating this assumption, the operator will + * signal {@link io.reactivex.rxjava3.exceptions.MissingBackpressureException}.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code MaybeSource}s that need to be eagerly concatenated + * @param maxConcurrency the maximum number of concurrently running inner {@code MaybeSource}s; {@link Integer#MAX_VALUE} + * is interpreted as all inner {@code MaybeSource}s can be active at the same time + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive + * @since 3.0.0 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Flowable concatEager(@NonNull Publisher<@NonNull ? extends MaybeSource> sources, int maxConcurrency) { + return Flowable.fromPublisher(sources).concatMapEager((Function)MaybeToPublisher.instance(), maxConcurrency, 1); + } + + /** + * Concatenates a sequence of {@link MaybeSource}s eagerly into a {@link Flowable} sequence, + * delaying errors until all inner {@code MaybeSource}s terminate. + *

+ * + *

+ * Eager concatenation means that once an observer subscribes, this operator subscribes to all of the + * source {@code MaybeSource}s. The operator buffers the values emitted by these {@code MaybeSource}s and then drains them + * in order, each one after the previous one completes. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code MaybeSource} that need to be eagerly concatenated + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Iterable<@NonNull ? extends MaybeSource> sources) { + return Flowable.fromIterable(sources).concatMapEagerDelayError((Function)MaybeToPublisher.instance(), true); + } + + /** + * Concatenates a sequence of {@link MaybeSource}s eagerly into a {@link Flowable} sequence, + * delaying errors until all inner {@code MaybeSource}s terminate and + * runs a limited number of inner {@code MaybeSource}s at once. + *

+ * + *

+ * Eager concatenation means that once an observer subscribes, this operator subscribes to all of the + * source {@code MaybeSource}s. The operator buffers the values emitted by these {@code MaybeSource}s and then drains them + * in order, each one after the previous one completes. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code MaybeSource} that need to be eagerly concatenated + * @param maxConcurrency the maximum number of concurrently running inner {@code MaybeSource}s; {@link Integer#MAX_VALUE} + * is interpreted as all inner {@code MaybeSource}s can be active at the same time + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive + * @since 3.0.0 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Iterable<@NonNull ? extends MaybeSource> sources, int maxConcurrency) { + return Flowable.fromIterable(sources).concatMapEagerDelayError((Function)MaybeToPublisher.instance(), true, maxConcurrency, 1); + } + + /** + * Concatenates a {@link Publisher} sequence of {@link MaybeSource}s eagerly into a {@link Flowable} sequence, + * delaying errors until all the inner and the outer sequence terminate. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * emitted source {@code MaybeSource}s as they are observed. The operator buffers the values emitted by these + * {@code MaybeSource}s and then drains them in order, each one after the previous one completes. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream and the outer {@code Publisher} is + * expected to support backpressure. Violating this assumption, the operator will + * signal {@link io.reactivex.rxjava3.exceptions.MissingBackpressureException}.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code MaybeSource}s that need to be eagerly concatenated + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Publisher<@NonNull ? extends MaybeSource> sources) { + return Flowable.fromPublisher(sources).concatMapEagerDelayError((Function)MaybeToPublisher.instance(), true); + } + + /** + * Concatenates a {@link Publisher} sequence of {@link MaybeSource}s eagerly into a {@link Flowable} sequence, + * delaying errors until all the inner and the outer sequence terminate and + * runs a limited number of the inner {@code MaybeSource}s at once. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * emitted source {@code MaybeSource}s as they are observed. The operator buffers the values emitted by these + * {@code MaybeSource}s and then drains them in order, each one after the previous one completes. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream and the outer {@code Publisher} is + * expected to support backpressure. Violating this assumption, the operator will + * signal {@link io.reactivex.rxjava3.exceptions.MissingBackpressureException}.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code MaybeSource}s that need to be eagerly concatenated + * @param maxConcurrency the maximum number of concurrently running inner {@code MaybeSource}s; {@link Integer#MAX_VALUE} + * is interpreted as all inner {@code MaybeSource}s can be active at the same time + * @return the new {@code Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive + * @since 3.0.0 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Publisher<@NonNull ? extends MaybeSource> sources, int maxConcurrency) { + return Flowable.fromPublisher(sources).concatMapEagerDelayError((Function)MaybeToPublisher.instance(), true, maxConcurrency, 1); + } + + /** + * Provides an API (via a cold {@code Maybe}) that bridges the reactive world with the callback-style world. + *

+ * *

* Example: *


@@ -571,68 +850,72 @@ public static  Flowable concatEager(@NonNull Publisher
      *  
Scheduler:
*
{@code create} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param onSubscribe the emitter that is called when a MaybeObserver subscribes to the returned {@code Maybe} - * @return the new Maybe instance + * @param onSubscribe the emitter that is called when a {@code MaybeObserver} subscribes to the returned {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code onSubscribe} is {@code null} * @see MaybeOnSubscribe * @see Cancellable */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe create(@NonNull MaybeOnSubscribe onSubscribe) { + public static <@NonNull T> Maybe create(@NonNull MaybeOnSubscribe onSubscribe) { Objects.requireNonNull(onSubscribe, "onSubscribe is null"); return RxJavaPlugins.onAssembly(new MaybeCreate<>(onSubscribe)); } /** - * Calls a Supplier for each individual MaybeObserver to return the actual MaybeSource source to + * Calls a {@link Supplier} for each individual {@link MaybeObserver} to return the actual {@link MaybeSource} source to * be subscribed to. + *

+ * *

*
Scheduler:
*
{@code defer} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param maybeSupplier the Supplier that is called for each individual MaybeObserver and - * returns a MaybeSource instance to subscribe to - * @return the new Maybe instance + * @param supplier the {@code Supplier} that is called for each individual {@code MaybeObserver} and + * returns a {@code MaybeSource} instance to subscribe to + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code supplier} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe defer(@NonNull Supplier> maybeSupplier) { - Objects.requireNonNull(maybeSupplier, "maybeSupplier is null"); - return RxJavaPlugins.onAssembly(new MaybeDefer<>(maybeSupplier)); + public static <@NonNull T> Maybe defer(@NonNull Supplier> supplier) { + Objects.requireNonNull(supplier, "supplier is null"); + return RxJavaPlugins.onAssembly(new MaybeDefer<>(supplier)); } /** - * Returns a (singleton) Maybe instance that calls {@link MaybeObserver#onComplete onComplete} + * Returns a (singleton) {@code Maybe} instance that calls {@link MaybeObserver#onComplete onComplete} * immediately. *

- * + * *

*
Scheduler:
*
{@code empty} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @return the new Maybe instance + * @return the shared {@code Maybe} instance */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @SuppressWarnings("unchecked") @NonNull - public static Maybe empty() { + public static <@NonNull T> Maybe empty() { return RxJavaPlugins.onAssembly((Maybe)MaybeEmpty.INSTANCE); } /** - * Returns a Maybe that invokes a subscriber's {@link MaybeObserver#onError onError} method when the + * Returns a {@code Maybe} that invokes a subscriber's {@link MaybeObserver#onError onError} method when the * subscriber subscribes to it. *

* @@ -641,127 +924,133 @@ public static Maybe empty() { *

{@code error} does not operate by default on a particular {@link Scheduler}.
*
* - * @param exception - * the particular Throwable to pass to {@link MaybeObserver#onError onError} + * @param throwable + * the particular {@link Throwable} to pass to {@link MaybeObserver#onError onError} * @param - * the type of the item (ostensibly) emitted by the Maybe - * @return a Maybe that invokes the subscriber's {@link MaybeObserver#onError onError} method when - * the subscriber subscribes to it + * the type of the item (ostensibly) emitted by the {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code throwable} is {@code null} * @see ReactiveX operators documentation: Throw */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe error(@NonNull Throwable exception) { - Objects.requireNonNull(exception, "exception is null"); - return RxJavaPlugins.onAssembly(new MaybeError<>(exception)); + public static <@NonNull T> Maybe error(@NonNull Throwable throwable) { + Objects.requireNonNull(throwable, "throwable is null"); + return RxJavaPlugins.onAssembly(new MaybeError<>(throwable)); } /** - * Returns a Maybe that invokes a {@link MaybeObserver}'s {@link MaybeObserver#onError onError} method when the - * MaybeObserver subscribes to it. + * Returns a {@code Maybe} that invokes a {@link MaybeObserver}'s {@link MaybeObserver#onError onError} method when the + * {@code MaybeObserver} subscribes to it. *

- * + * *

*
Scheduler:
*
{@code error} does not operate by default on a particular {@link Scheduler}.
*
* * @param supplier - * a Supplier factory to return a Throwable for each individual MaybeObserver + * a {@link Supplier} factory to return a {@link Throwable} for each individual {@code MaybeObserver} * @param - * the type of the items (ostensibly) emitted by the Maybe - * @return a Maybe that invokes the {@link MaybeObserver}'s {@link MaybeObserver#onError onError} method when - * the MaybeObserver subscribes to it + * the type of the items (ostensibly) emitted by the {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code supplier} is {@code null} * @see ReactiveX operators documentation: Throw */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe error(@NonNull Supplier supplier) { + public static <@NonNull T> Maybe error(@NonNull Supplier supplier) { Objects.requireNonNull(supplier, "supplier is null"); return RxJavaPlugins.onAssembly(new MaybeErrorCallable<>(supplier)); } /** - * Returns a Maybe instance that runs the given Action for each subscriber and + * Returns a {@code Maybe} instance that runs the given {@link Action} for each {@link MaybeObserver} and * emits either its exception or simply completes. + *

+ * *

*
Scheduler:
*
{@code fromAction} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If the {@link Action} throws an exception, the respective {@link Throwable} is + *
If the {@code Action} throws an exception, the respective {@link Throwable} is * delivered to the downstream via {@link MaybeObserver#onError(Throwable)}, - * except when the downstream has disposed this {@code Maybe} source. + * except when the downstream has disposed the resulting {@code Maybe} source. * In this latter case, the {@code Throwable} is delivered to the global error handler via * {@link RxJavaPlugins#onError(Throwable)} as an {@link io.reactivex.rxjava3.exceptions.UndeliverableException UndeliverableException}. *
*
* @param the target type - * @param run the runnable to run for each subscriber - * @return the new Maybe instance - * @throws NullPointerException if run is null + * @param action the {@code Action} to run for each {@code MaybeObserver} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code action} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe fromAction(@NonNull Action run) { - Objects.requireNonNull(run, "run is null"); - return RxJavaPlugins.onAssembly(new MaybeFromAction<>(run)); + public static <@NonNull T> Maybe fromAction(@NonNull Action action) { + Objects.requireNonNull(action, "action is null"); + return RxJavaPlugins.onAssembly(new MaybeFromAction<>(action)); } /** - * Wraps a CompletableSource into a Maybe. - * + * Wraps a {@link CompletableSource} into a {@code Maybe}. + *

+ * *

*
Scheduler:
*
{@code fromCompletable} does not operate by default on a particular {@link Scheduler}.
*
* @param the target type - * @param completableSource the CompletableSource to convert from - * @return the new Maybe instance - * @throws NullPointerException if completable is null + * @param completableSource the {@code CompletableSource} to convert from + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code completableSource} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe fromCompletable(@NonNull CompletableSource completableSource) { + public static <@NonNull T> Maybe fromCompletable(@NonNull CompletableSource completableSource) { Objects.requireNonNull(completableSource, "completableSource is null"); return RxJavaPlugins.onAssembly(new MaybeFromCompletable<>(completableSource)); } /** - * Wraps a SingleSource into a Maybe. - * + * Wraps a {@link SingleSource} into a {@code Maybe}. + *

+ * *

*
Scheduler:
*
{@code fromSingle} does not operate by default on a particular {@link Scheduler}.
*
* @param the target type - * @param singleSource the SingleSource to convert from - * @return the new Maybe instance - * @throws NullPointerException if single is null + * @param single the {@code SingleSource} to convert from + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code single} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe fromSingle(@NonNull SingleSource singleSource) { - Objects.requireNonNull(singleSource, "singleSource is null"); - return RxJavaPlugins.onAssembly(new MaybeFromSingle<>(singleSource)); + public static <@NonNull T> Maybe fromSingle(@NonNull SingleSource single) { + Objects.requireNonNull(single, "single is null"); + return RxJavaPlugins.onAssembly(new MaybeFromSingle<>(single)); } /** - * Returns a {@link Maybe} that invokes the given {@link Callable} for each individual {@link MaybeObserver} that - * subscribes and emits the resulting non-null item via {@code onSuccess} while + * Returns a {@code Maybe} that invokes the given {@link Callable} for each individual {@link MaybeObserver} that + * subscribes and emits the resulting non-{@code null} item via {@code onSuccess} while * considering a {@code null} result from the {@code Callable} as indication for valueless completion * via {@code onComplete}. *

+ * + *

* This operator allows you to defer the execution of the given {@code Callable} until a {@code MaybeObserver} - * subscribes to the returned {@link Maybe}. In other terms, this source operator evaluates the given + * subscribes to the returned {@code Maybe}. In other terms, this source operator evaluates the given * {@code Callable} "lazily". *

* Note that the {@code null} handling of this operator differs from the similar source operators in the other - * {@link io.reactivex.rxjava3.core base reactive classes}. Those operators signal a {@code NullPointerException} if the value returned by their + * {@link io.reactivex.rxjava3.core base reactive classes}. Those operators signal a {@link NullPointerException} if the value returned by their * {@code Callable} is {@code null} while this {@code fromCallable} considers it to indicate the * returned {@code Maybe} is empty. *

@@ -778,47 +1067,49 @@ public static Maybe fromSingle(@NonNull SingleSource singleSource) { *
* * @param callable - * a {@link Callable} instance whose execution should be deferred and performed for each individual - * {@code MaybeObserver} that subscribes to the returned {@link Maybe}. + * a {@code Callable} instance whose execution should be deferred and performed for each individual + * {@code MaybeObserver} that subscribes to the returned {@code Maybe}. * @param - * the type of the item emitted by the {@link Maybe}. - * @return a new Maybe instance + * the type of the item emitted by the {@code Maybe}. + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code callable} is {@code null} * @see #defer(Supplier) * @see #fromSupplier(Supplier) */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static <@NonNull T> Maybe fromCallable(@NonNull Callable callable) { + public static Maybe<@NonNull T> fromCallable(@NonNull Callable callable) { Objects.requireNonNull(callable, "callable is null"); return RxJavaPlugins.onAssembly(new MaybeFromCallable<>(callable)); } /** - * Converts a {@link Future} into a Maybe, treating a null result as an indication of emptiness. - *

- * + * Converts a {@link Future} into a {@code Maybe}, treating a {@code null} result as an indication of emptiness. *

- * You can convert any object that supports the {@link Future} interface into a Maybe that emits the - * return value of the {@link Future#get} method of that object, by passing the object into the {@code from} - * method. + * *

- * Important note: This Maybe is blocking; you cannot dispose it. + * The operator calls {@link Future#get()}, which is a blocking method, on the subscription thread. + * It is recommended applying {@link #subscribeOn(Scheduler)} to move this blocking wait to a + * background thread, and if the {@link Scheduler} supports it, interrupt the wait when the flow + * is disposed. *

- * Unlike 1.x, disposing the Maybe won't cancel the future. If necessary, one can use composition to achieve the + * Unlike 1.x, disposing the {@code Maybe} won't cancel the future. If necessary, one can use composition to achieve the * cancellation effect: {@code futureMaybe.doOnDispose(() -> future.cancel(true));}. *

*
Scheduler:
- *
{@code fromFuture} does not operate by default on a particular {@link Scheduler}.
+ *
{@code fromFuture} does not operate by default on a particular {@code Scheduler}.
*
* * @param future - * the source {@link Future} + * the source {@code Future} * @param - * the type of object that the {@link Future} returns, and also the type of item to be emitted by - * the resulting Maybe - * @return a Maybe that emits the item from the source {@link Future} + * the type of object that the {@code Future} returns, and also the type of item to be emitted by + * the resulting {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code future} is {@code null} * @see ReactiveX operators documentation: From + * @see #fromCompletionStage(CompletionStage) */ @CheckReturnValue @NonNull @@ -829,34 +1120,35 @@ public static Maybe fromSingle(@NonNull SingleSource singleSource) { } /** - * Converts a {@link Future} into a Maybe, with a timeout on the Future. + * Converts a {@link Future} into a {@code Maybe}, with a timeout on the {@code Future}. *

- * + * *

- * You can convert any object that supports the {@link Future} interface into a Maybe that emits the - * return value of the {@link Future#get} method of that object, by passing the object into the {@code fromFuture} - * method. + * The operator calls {@link Future#get(long, TimeUnit)}, which is a blocking method, on the subscription thread. + * It is recommended applying {@link #subscribeOn(Scheduler)} to move this blocking wait to a + * background thread, and if the {@link Scheduler} supports it, interrupt the wait when the flow + * is disposed. *

- * Unlike 1.x, disposing the Maybe won't cancel the future. If necessary, one can use composition to achieve the + * Unlike 1.x, disposing the {@code Maybe} won't cancel the future. If necessary, one can use composition to achieve the * cancellation effect: {@code futureMaybe.doOnCancel(() -> future.cancel(true));}. - *

- * Important note: This Maybe is blocking on the thread it gets subscribed on; you cannot dispose it. *

*
Scheduler:
- *
{@code fromFuture} does not operate by default on a particular {@link Scheduler}.
+ *
{@code fromFuture} does not operate by default on a particular {@code Scheduler}.
*
* * @param future - * the source {@link Future} + * the source {@code Future} * @param timeout * the maximum time to wait before calling {@code get} * @param unit * the {@link TimeUnit} of the {@code timeout} argument * @param - * the type of object that the {@link Future} returns, and also the type of item to be emitted by - * the resulting Maybe - * @return a Maybe that emits the item from the source {@link Future} + * the type of object that the {@code Future} returns, and also the type of item to be emitted by + * the resulting {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code future} or {@code unit} is {@code null} * @see ReactiveX operators documentation: From + * @see #fromCompletionStage(CompletionStage) */ @CheckReturnValue @NonNull @@ -868,39 +1160,104 @@ public static Maybe fromSingle(@NonNull SingleSource singleSource) { } /** - * Returns a Maybe instance that runs the given Action for each subscriber and - * emits either its exception or simply completes. + * Wraps an {@link ObservableSource} into a {@code Maybe} and emits the very first item + * or completes if the source is empty. + *

+ * + *

+ *
Scheduler:
+ *
{@code fromObservable} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the target type + * @param source the {@code ObservableSource} to convert from + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code source} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Maybe fromObservable(@NonNull ObservableSource source) { + Objects.requireNonNull(source, "source is null"); + return RxJavaPlugins.onAssembly(new ObservableElementAtMaybe<>(source, 0L)); + } + + /** + * Wraps a {@link Publisher} into a {@code Maybe} and emits the very first item + * or completes if the source is empty. + *

+ * + *

+ *
Backpressure:
+ *
The operator consumes the given {@code Publisher} in an unbounded manner + * (requesting {@link Long#MAX_VALUE}) but cancels it after one item received.
+ *
Scheduler:
+ *
{@code fromPublisher} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the target type + * @param source the {@code Publisher} to convert from + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code source} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) + public static <@NonNull T> Maybe fromPublisher(@NonNull Publisher source) { + Objects.requireNonNull(source, "source is null"); + return RxJavaPlugins.onAssembly(new FlowableElementAtMaybePublisher<>(source, 0L)); + } + + /** + * Returns a {@code Maybe} instance that runs the given {@link Runnable} for each {@link MaybeObserver} and + * emits either its unchecked exception or simply completes. + *

+ * + *

+ * If the code to be wrapped needs to throw a checked or more broader {@link Throwable} exception, that + * exception has to be converted to an unchecked exception by the wrapped code itself. Alternatively, + * use the {@link #fromAction(Action)} method which allows the wrapped code to throw any {@code Throwable} + * exception and will signal it to observers as-is. *

*
Scheduler:
*
{@code fromRunnable} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If the {@code Runnable} throws an exception, the respective {@code Throwable} is + * delivered to the downstream via {@link MaybeObserver#onError(Throwable)}, + * except when the downstream has disposed this {@code Maybe} source. + * In this latter case, the {@code Throwable} is delivered to the global error handler via + * {@link RxJavaPlugins#onError(Throwable)} as an {@link io.reactivex.rxjava3.exceptions.UndeliverableException UndeliverableException}. + *
*
* @param the target type - * @param run the runnable to run for each subscriber - * @return the new Maybe instance - * @throws NullPointerException if run is null + * @param run the {@code Runnable} to run for each {@code MaybeObserver} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code run} is {@code null} + * @see #fromAction(Action) */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe fromRunnable(@NonNull Runnable run) { + public static <@NonNull T> Maybe fromRunnable(@NonNull Runnable run) { Objects.requireNonNull(run, "run is null"); return RxJavaPlugins.onAssembly(new MaybeFromRunnable<>(run)); } /** - * Returns a {@link Maybe} that invokes the given {@link Supplier} for each individual {@link MaybeObserver} that - * subscribes and emits the resulting non-null item via {@code onSuccess} while + * Returns a {@code Maybe} that invokes the given {@link Supplier} for each individual {@link MaybeObserver} that + * subscribes and emits the resulting non-{@code null} item via {@code onSuccess} while * considering a {@code null} result from the {@code Supplier} as indication for valueless completion * via {@code onComplete}. *

* This operator allows you to defer the execution of the given {@code Supplier} until a {@code MaybeObserver} - * subscribes to the returned {@link Maybe}. In other terms, this source operator evaluates the given + * subscribes to the returned {@code Maybe}. In other terms, this source operator evaluates the given * {@code Supplier} "lazily". *

- * + * *

* Note that the {@code null} handling of this operator differs from the similar source operators in the other - * {@link io.reactivex.rxjava3.core base reactive classes}. Those operators signal a {@code NullPointerException} if the value returned by their + * {@link io.reactivex.rxjava3.core base reactive classes}. Those operators signal a {@link NullPointerException} if the value returned by their * {@code Supplier} is {@code null} while this {@code fromSupplier} considers it to indicate the * returned {@code Maybe} is empty. *

@@ -917,11 +1274,12 @@ public static Maybe fromRunnable(@NonNull Runnable run) { *
* * @param supplier - * a {@link Supplier} instance whose execution should be deferred and performed for each individual - * {@code MaybeObserver} that subscribes to the returned {@link Maybe}. + * a {@code Supplier} instance whose execution should be deferred and performed for each individual + * {@code MaybeObserver} that subscribes to the returned {@code Maybe}. * @param - * the type of the item emitted by the {@link Maybe}. - * @return a new Maybe instance + * the type of the item emitted by the {@code Maybe}. + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code supplier} is {@code null} * @see #defer(Supplier) * @see #fromCallable(Callable) * @since 3.0.0 @@ -929,7 +1287,7 @@ public static Maybe fromRunnable(@NonNull Runnable run) { @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static <@NonNull T> Maybe fromSupplier(@NonNull Supplier supplier) { + public static Maybe<@NonNull T> fromSupplier(@NonNull Supplier supplier) { Objects.requireNonNull(supplier, "supplier is null"); return RxJavaPlugins.onAssembly(new MaybeFromSupplier<>(supplier)); } @@ -950,7 +1308,8 @@ public static Maybe fromRunnable(@NonNull Runnable run) { * the item to emit * @param * the type of that item - * @return a {@code Maybe} that emits {@code item} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code item} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @@ -962,21 +1321,23 @@ public static Maybe fromRunnable(@NonNull Runnable run) { } /** - * Merges an Iterable sequence of MaybeSource instances into a single Flowable sequence, - * running all MaybeSources at once. + * Merges an {@link Iterable} sequence of {@link MaybeSource} instances into a single {@link Flowable} sequence, + * running all {@code MaybeSource}s at once. + *

+ * *

*
Backpressure:
*
The operator honors backpressure from downstream.
*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code MaybeSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the source {@code MaybeSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Flowable} terminates with that {@code Throwable} and all other source {@code MaybeSource}s are disposed. * If more than one {@code MaybeSource} signals an error, the resulting {@code Flowable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(Iterable)} to merge sources and terminate only when all source {@code MaybeSource}s @@ -984,34 +1345,37 @@ public static Maybe fromRunnable(@NonNull Runnable run) { *
*
* @param the common and resulting value type - * @param sources the Iterable sequence of MaybeSource sources - * @return the new Flowable instance + * @param sources the {@code Iterable} sequence of {@code MaybeSource} sources + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see #mergeDelayError(Iterable) */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable merge(@NonNull Iterable> sources) { - return merge(Flowable.fromIterable(sources)); + public static <@NonNull T> Flowable merge(@NonNull Iterable<@NonNull ? extends MaybeSource> sources) { + return Flowable.fromIterable(sources).flatMapMaybe(Functions.identity(), false, Integer.MAX_VALUE); } /** - * Merges a Flowable sequence of MaybeSource instances into a single Flowable sequence, - * running all MaybeSources at once. + * Merges a {@link Publisher} sequence of {@link MaybeSource} instances into a single {@link Flowable} sequence, + * running all {@code MaybeSource}s at once. + *

+ * *

*
Backpressure:
*
The operator honors backpressure from downstream.
*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code MaybeSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the source {@code MaybeSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Flowable} terminates with that {@code Throwable} and all other source {@code MaybeSource}s are disposed. * If more than one {@code MaybeSource} signals an error, the resulting {@code Flowable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(Publisher)} to merge sources and terminate only when all source {@code MaybeSource}s @@ -1019,34 +1383,37 @@ public static Flowable merge(@NonNull Iterable *
* @param the common and resulting value type - * @param sources the Flowable sequence of MaybeSource sources - * @return the new Flowable instance + * @param sources the {@code Flowable} sequence of {@code MaybeSource} sources + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see #mergeDelayError(Publisher) */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable merge(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable merge(@NonNull Publisher<@NonNull ? extends MaybeSource> sources) { return merge(sources, Integer.MAX_VALUE); } /** - * Merges a Flowable sequence of MaybeSource instances into a single Flowable sequence, - * running at most maxConcurrency MaybeSources at once. + * Merges a {@link Publisher} sequence of {@link MaybeSource} instances into a single {@link Flowable} sequence, + * running at most maxConcurrency {@code MaybeSource}s at once. + *

+ * *

*
Backpressure:
*
The operator honors backpressure from downstream.
*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code MaybeSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the source {@code MaybeSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Flowable} terminates with that {@code Throwable} and all other source {@code MaybeSource}s are disposed. * If more than one {@code MaybeSource} signals an error, the resulting {@code Flowable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(Publisher, int)} to merge sources and terminate only when all source {@code MaybeSource}s @@ -1054,33 +1421,34 @@ public static Flowable merge(@NonNull Publisher *
* @param the common and resulting value type - * @param sources the Flowable sequence of MaybeSource sources - * @param maxConcurrency the maximum number of concurrently running MaybeSources - * @return the new Flowable instance + * @param sources the {@code Flowable} sequence of {@code MaybeSource} sources + * @param maxConcurrency the maximum number of concurrently running {@code MaybeSource}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see #mergeDelayError(Publisher, int) */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Flowable merge(@NonNull Publisher> sources, int maxConcurrency) { + public static <@NonNull T> Flowable merge(@NonNull Publisher<@NonNull ? extends MaybeSource> sources, int maxConcurrency) { Objects.requireNonNull(sources, "sources is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); - return RxJavaPlugins.onAssembly(new FlowableFlatMapPublisher(sources, MaybeToPublisher.instance(), false, maxConcurrency, 1)); + return RxJavaPlugins.onAssembly(new FlowableFlatMapMaybePublisher<>(sources, Functions.identity(), false, maxConcurrency)); } /** - * Flattens a {@code MaybeSource} that emits a {@code MaybeSource} into a single {@code MaybeSource} that emits the item + * Flattens a {@link MaybeSource} that emits a {@code MaybeSource} into a single {@code MaybeSource} that emits the item * emitted by the nested {@code MaybeSource}, without any transformation. *

- * + * *

*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
The resulting {@code Maybe} emits the outer source's or the inner {@code MaybeSource}'s {@code Throwable} as is. - * Unlike the other {@code merge()} operators, this operator won't and can't produce a {@code CompositeException} because there is + *
The resulting {@code Maybe} emits the outer source's or the inner {@code MaybeSource}'s {@link Throwable} as is. + * Unlike the other {@code merge()} operators, this operator won't and can't produce a {@link CompositeException} because there is * only one possibility for the outer or the inner {@code MaybeSource} to emit an {@code onError} signal. * Therefore, there is no need for a {@code mergeDelayError(MaybeSource>)} operator. *
@@ -1089,25 +1457,25 @@ public static Flowable merge(@NonNull Publisher the value type of the sources and the output * @param source * a {@code MaybeSource} that emits a {@code MaybeSource} - * @return a {@code Maybe} that emits the item that is the result of flattening the {@code MaybeSource} emitted - * by {@code source} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code source} is {@code null} * @see ReactiveX operators documentation: Merge */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Maybe merge(@NonNull MaybeSource> source) { + public static <@NonNull T> Maybe merge(@NonNull MaybeSource> source) { Objects.requireNonNull(source, "source is null"); return RxJavaPlugins.onAssembly(new MaybeFlatten(source, Functions.identity())); } /** - * Flattens two MaybeSources into a single Flowable, without any transformation. + * Flattens two {@link MaybeSource}s into a single {@link Flowable}, without any transformation. *

- * + * *

- * You can combine items emitted by multiple MaybeSources so that they appear as a single Flowable, by + * You can combine items emitted by multiple {@code MaybeSource}s so that they appear as a single {@code Flowable}, by * using the {@code merge} method. *

*
Backpressure:
@@ -1115,13 +1483,13 @@ public static Maybe merge(@NonNull MaybeSourceScheduler: *
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code MaybeSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the source {@code MaybeSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Flowable} terminates with that {@code Throwable} and all other source {@code MaybeSource}s are disposed. * If more than one {@code MaybeSource} signals an error, the resulting {@code Flowable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(MaybeSource, MaybeSource)} to merge sources and terminate only when all source {@code MaybeSource}s @@ -1131,10 +1499,11 @@ public static Maybe merge(@NonNull MaybeSource the common value type * @param source1 - * a MaybeSource to be merged + * a {@code MaybeSource} to be merged * @param source2 - * a MaybeSource to be merged - * @return a Flowable that emits all of the items emitted by the source MaybeSources + * a {@code MaybeSource} to be merged + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(MaybeSource, MaybeSource) */ @@ -1142,7 +1511,7 @@ public static Maybe merge(@NonNull MaybeSource Flowable merge( + public static <@NonNull T> Flowable merge( @NonNull MaybeSource source1, @NonNull MaybeSource source2 ) { Objects.requireNonNull(source1, "source1 is null"); @@ -1151,11 +1520,11 @@ public static Flowable merge( } /** - * Flattens three MaybeSources into a single Flowable, without any transformation. + * Flattens three {@link MaybeSource}s into a single {@link Flowable}, without any transformation. *

- * + * *

- * You can combine items emitted by multiple MaybeSources so that they appear as a single Flowable, by using + * You can combine items emitted by multiple {@code MaybeSource}s so that they appear as a single {@code Flowable}, by using * the {@code merge} method. *

*
Backpressure:
@@ -1163,13 +1532,13 @@ public static Flowable merge( *
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code MaybeSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the source {@code MaybeSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Flowable} terminates with that {@code Throwable} and all other source {@code MaybeSource}s are disposed. * If more than one {@code MaybeSource} signals an error, the resulting {@code Flowable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(MaybeSource, MaybeSource, MaybeSource)} to merge sources and terminate only when all source {@code MaybeSource}s @@ -1179,12 +1548,13 @@ public static Flowable merge( * * @param the common value type * @param source1 - * a MaybeSource to be merged + * a {@code MaybeSource} to be merged * @param source2 - * a MaybeSource to be merged + * a {@code MaybeSource} to be merged * @param source3 - * a MaybeSource to be merged - * @return a Flowable that emits all of the items emitted by the source MaybeSources + * a {@code MaybeSource} to be merged + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(MaybeSource, MaybeSource, MaybeSource) */ @@ -1192,7 +1562,7 @@ public static Flowable merge( @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable merge( + public static <@NonNull T> Flowable merge( @NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull MaybeSource source3 ) { @@ -1203,11 +1573,11 @@ public static Flowable merge( } /** - * Flattens four MaybeSources into a single Flowable, without any transformation. + * Flattens four {@link MaybeSource}s into a single {@link Flowable}, without any transformation. *

- * + * *

- * You can combine items emitted by multiple MaybeSources so that they appear as a single Flowable, by using + * You can combine items emitted by multiple {@code MaybeSource}s so that they appear as a single {@code Flowable}, by using * the {@code merge} method. *

*
Backpressure:
@@ -1215,13 +1585,13 @@ public static Flowable merge( *
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code MaybeSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the source {@code MaybeSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Flowable} terminates with that {@code Throwable} and all other source {@code MaybeSource}s are disposed. * If more than one {@code MaybeSource} signals an error, the resulting {@code Flowable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(MaybeSource, MaybeSource, MaybeSource, MaybeSource)} to merge sources and terminate only when all source {@code MaybeSource}s @@ -1231,14 +1601,15 @@ public static Flowable merge( * * @param the common value type * @param source1 - * a MaybeSource to be merged + * a {@code MaybeSource} to be merged * @param source2 - * a MaybeSource to be merged + * a {@code MaybeSource} to be merged * @param source3 - * a MaybeSource to be merged + * a {@code MaybeSource} to be merged * @param source4 - * a MaybeSource to be merged - * @return a Flowable that emits all of the items emitted by the source MaybeSources + * a {@code MaybeSource} to be merged + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(MaybeSource, MaybeSource, MaybeSource, MaybeSource) */ @@ -1246,7 +1617,7 @@ public static Flowable merge( @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable merge( + public static <@NonNull T> Flowable merge( @NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull MaybeSource source3, @NonNull MaybeSource source4 ) { @@ -1258,21 +1629,23 @@ public static Flowable merge( } /** - * Merges an array sequence of MaybeSource instances into a single Flowable sequence, - * running all MaybeSources at once. + * Merges an array of {@link MaybeSource} instances into a single {@link Flowable} sequence, + * running all {@code MaybeSource}s at once. + *

+ * *

*
Backpressure:
*
The operator honors backpressure from downstream.
*
Scheduler:
*
{@code mergeArray} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code MaybeSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the source {@code MaybeSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Flowable} terminates with that {@code Throwable} and all other source {@code MaybeSource}s are disposed. * If more than one {@code MaybeSource} signals an error, the resulting {@code Flowable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeArrayDelayError(MaybeSource...)} to merge sources and terminate only when all source {@code MaybeSource}s @@ -1280,8 +1653,9 @@ public static Flowable merge( *
*
* @param the common and resulting value type - * @param sources the array sequence of MaybeSource sources - * @return the new Flowable instance + * @param sources the array sequence of {@code MaybeSource} sources + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see #mergeArrayDelayError(MaybeSource...) */ @BackpressureSupport(BackpressureKind.FULL) @@ -1289,7 +1663,7 @@ public static Flowable merge( @NonNull @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs - public static Flowable mergeArray(MaybeSource... sources) { + public static <@NonNull T> Flowable mergeArray(MaybeSource... sources) { Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { return Flowable.empty(); @@ -1303,18 +1677,18 @@ public static Flowable mergeArray(MaybeSource... sources) { } /** - * Flattens an array of MaybeSources into one Flowable, in a way that allows a Subscriber to receive all - * successfully emitted items from each of the source MaybeSources without being interrupted by an error + * Flattens an array of {@link MaybeSource}s into one {@link Flowable}, in a way that allows a subscriber to receive all + * successfully emitted items from each of the source {@code MaybeSource}s without being interrupted by an error * notification from one of them. *

- * This behaves like {@link #merge(Publisher)} except that if any of the merged MaybeSources notify of an - * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged MaybeSources have finished emitting items. + * *

- * + * This behaves like {@link #merge(Publisher)} except that if any of the merged {@code MaybeSource}s notify of an + * error via {@link Subscriber#onError onError}, {@code mergeArrayDelayError} will refrain from propagating that + * error notification until all of the merged {@code MaybeSource}s have finished emitting items. *

- * Even if multiple merged MaybeSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Subscribers once. + * Even if multiple merged {@code MaybeSource}s send {@code onError} notifications, {@code mergeArrayDelayError} will only + * invoke the {@code onError} method of its subscribers once. *

*
Backpressure:
*
The operator honors backpressure from downstream.
@@ -1324,37 +1698,36 @@ public static Flowable mergeArray(MaybeSource... sources) { * * @param the common element base type * @param sources - * the Iterable of MaybeSources - * @return a Flowable that emits items that are the result of flattening the items emitted by the - * MaybeSources in the Iterable + * the array of {@code MaybeSource}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs @NonNull - public static Flowable mergeArrayDelayError(@NonNull MaybeSource... sources) { - if (sources.length == 0) { - return Flowable.empty(); - } - return Flowable.fromArray(sources).flatMap((Function)MaybeToPublisher.instance(), true, sources.length); + public static <@NonNull T> Flowable mergeArrayDelayError(@NonNull MaybeSource... sources) { + Objects.requireNonNull(sources, "sources is null"); + return Flowable.fromArray(sources).flatMapMaybe(Functions.identity(), true, Math.max(1, sources.length)); } /** - * Flattens an Iterable of MaybeSources into one Flowable, in a way that allows a Subscriber to receive all - * successfully emitted items from each of the source MaybeSources without being interrupted by an error + * Flattens an {@link Iterable} sequence of {@link MaybeSource}s into one {@link Flowable}, in a way that allows a subscriber to receive all + * successfully emitted items from each of the source {@code MaybeSource}s without being interrupted by an error * notification from one of them. *

- * This behaves like {@link #merge(Publisher)} except that if any of the merged MaybeSources notify of an + * + *

+ * This behaves like {@link #merge(Publisher)} except that if any of the merged {@code MaybeSource}s notify of an * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged MaybeSources have finished emitting items. + * error notification until all of the merged {@code MaybeSource}s have finished emitting items. *

- * + * *

- * Even if multiple merged MaybeSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Subscribers once. + * Even if multiple merged {@code MaybeSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its subscribers once. *

*
Backpressure:
*
The operator honors backpressure from downstream.
@@ -1364,33 +1737,32 @@ public static Flowable mergeArrayDelayError(@NonNull MaybeSource the common element base type * @param sources - * the Iterable of MaybeSources - * @return a Flowable that emits items that are the result of flattening the items emitted by the - * MaybeSources in the Iterable + * the {@code Iterable} of {@code MaybeSource}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable mergeDelayError(@NonNull Iterable> sources) { - return Flowable.fromIterable(sources).flatMap((Function)MaybeToPublisher.instance(), true); + public static <@NonNull T> Flowable mergeDelayError(@NonNull Iterable<@NonNull ? extends MaybeSource> sources) { + return Flowable.fromIterable(sources).flatMapMaybe(Functions.identity(), true, Integer.MAX_VALUE); } /** - * Flattens a Publisher that emits MaybeSources into one Publisher, in a way that allows a Subscriber to - * receive all successfully emitted items from all of the source MaybeSources without being interrupted by - * an error notification from one of them or even the main Publisher. + * Flattens a {@link Publisher} that emits {@link MaybeSource}s into one {@link Flowable}, in a way that allows a subscriber to + * receive all successfully emitted items from all of the source {@code MaybeSource}s without being interrupted by + * an error notification from one of them or even the main {@code Publisher}. *

- * This behaves like {@link #merge(Publisher)} except that if any of the merged MaybeSources notify of an - * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged MaybeSources and the main Publisher have finished emitting items. + * *

- * + * This behaves like {@link #merge(Publisher)} except that if any of the merged {@code MaybeSource}s notify of an + * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that + * error notification until all of the merged {@code MaybeSource}s and the main {@code Publisher} have finished emitting items. *

- * Even if multiple merged Publishers send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Subscribers once. + * Even if multiple merged {@code MaybeSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its subscribers once. *

*
Backpressure:
*
The operator honors backpressure from downstream. The outer {@code Publisher} is consumed @@ -1401,32 +1773,32 @@ public static Flowable mergeDelayError(@NonNull Iterable the common element base type * @param sources - * a Publisher that emits MaybeSources - * @return a Flowable that emits all of the items emitted by the Publishers emitted by the - * {@code source} Publisher + * a {@code Publisher} that emits {@code MaybeSource}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Flowable mergeDelayError(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable mergeDelayError(@NonNull Publisher<@NonNull ? extends MaybeSource> sources) { return mergeDelayError(sources, Integer.MAX_VALUE); } /** - * Flattens a Publisher that emits MaybeSources into one Publisher, in a way that allows a Subscriber to - * receive all successfully emitted items from all of the source MaybeSources without being interrupted by - * an error notification from one of them or even the main Publisher as well as limiting the total number of active MaybeSources. + * Flattens a {@link Publisher} that emits {@link MaybeSource}s into one {@link Flowable}, in a way that allows a subscriber to + * receive all successfully emitted items from all of the source {@code MaybeSource}s without being interrupted by + * an error notification from one of them or even the main {@code Publisher} as well as limiting the total number of active {@code MaybeSource}s. *

- * This behaves like {@link #merge(Publisher, int)} except that if any of the merged MaybeSources notify of an - * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged MaybeSources and the main Publisher have finished emitting items. + * *

- * + * This behaves like {@link #merge(Publisher, int)} except that if any of the merged {@code MaybeSource}s notify of an + * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that + * error notification until all of the merged {@code MaybeSource}s and the main {@code Publisher} have finished emitting items. *

- * Even if multiple merged Publishers send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Subscribers once. + * Even if multiple merged {@code MaybeSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its subscribers once. *

*
Backpressure:
*
The operator honors backpressure from downstream. The outer {@code Publisher} is consumed @@ -1437,37 +1809,37 @@ public static Flowable mergeDelayError(@NonNull PublisherHistory: 2.1.9 - experimental * @param the common element base type * @param sources - * a Publisher that emits MaybeSources - * @param maxConcurrency the maximum number of active inner MaybeSources to be merged at a time - * @return a Flowable that emits all of the items emitted by the Publishers emitted by the - * {@code source} Publisher + * a {@code Publisher} that emits {@code MaybeSource}s + * @param maxConcurrency the maximum number of active inner {@code MaybeSource}s to be merged at a time + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: Merge * @since 2.2 */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable mergeDelayError(@NonNull Publisher> sources, int maxConcurrency) { + public static <@NonNull T> Flowable mergeDelayError(@NonNull Publisher<@NonNull ? extends MaybeSource> sources, int maxConcurrency) { Objects.requireNonNull(sources, "sources is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); - return RxJavaPlugins.onAssembly(new FlowableFlatMapPublisher(sources, MaybeToPublisher.instance(), true, maxConcurrency, 1)); + return RxJavaPlugins.onAssembly(new FlowableFlatMapMaybePublisher<>(sources, Functions.identity(), true, maxConcurrency)); } /** - * Flattens two MaybeSources into one Flowable, in a way that allows a Subscriber to receive all - * successfully emitted items from each of the source MaybeSources without being interrupted by an error + * Flattens two {@link MaybeSource}s into one {@link Flowable}, in a way that allows a subscriber to receive all + * successfully emitted items from each of the source {@code MaybeSource}s without being interrupted by an error * notification from one of them. *

- * This behaves like {@link #merge(MaybeSource, MaybeSource)} except that if any of the merged MaybeSources - * notify of an error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from - * propagating that error notification until all of the merged MaybeSources have finished emitting items. + * *

- * + * This behaves like {@link #merge(MaybeSource, MaybeSource)} except that if any of the merged {@code MaybeSource}s + * notify of an error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from + * propagating that error notification until all of the merged {@code MaybeSource}s have finished emitting items. *

- * Even if both merged MaybeSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Subscribers once. + * Even if both merged {@code MaybeSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its subscribers once. *

*
Backpressure:
*
The operator honors backpressure from downstream.
@@ -1477,36 +1849,37 @@ public static Flowable mergeDelayError(@NonNull Publisher the common element base type * @param source1 - * a MaybeSource to be merged + * a {@code MaybeSource} to be merged * @param source2 - * a MaybeSource to be merged - * @return a Flowable that emits all of the items that are emitted by the two source MaybeSources + * a {@code MaybeSource} to be merged + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @see ReactiveX operators documentation: Merge */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable mergeDelayError(@NonNull MaybeSource source1, @NonNull MaybeSource source2) { + public static <@NonNull T> Flowable mergeDelayError(@NonNull MaybeSource source1, @NonNull MaybeSource source2) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); return mergeArrayDelayError(source1, source2); } /** - * Flattens three MaybeSource into one Flowable, in a way that allows a Subscriber to receive all - * successfully emitted items from all of the source MaybeSources without being interrupted by an error + * Flattens three {@link MaybeSource} into one {@link Flowable}, in a way that allows a subscriber to receive all + * successfully emitted items from all of the source {@code MaybeSource}s without being interrupted by an error * notification from one of them. *

+ * + *

* This behaves like {@link #merge(MaybeSource, MaybeSource, MaybeSource)} except that if any of the merged - * MaybeSources notify of an error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain - * from propagating that error notification until all of the merged MaybeSources have finished emitting + * {@code MaybeSource}s notify of an error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain + * from propagating that error notification until all of the merged {@code MaybeSource}s have finished emitting * items. *

- * - *

- * Even if multiple merged MaybeSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Subscribers once. + * Even if multiple merged {@code MaybeSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its subscribers once. *

*
Backpressure:
*
The operator honors backpressure from downstream.
@@ -1516,19 +1889,20 @@ public static Flowable mergeDelayError(@NonNull MaybeSource * * @param the common element base type * @param source1 - * a MaybeSource to be merged + * a {@code MaybeSource} to be merged * @param source2 - * a MaybeSource to be merged + * a {@code MaybeSource} to be merged * @param source3 - * a MaybeSource to be merged - * @return a Flowable that emits all of the items that are emitted by the source MaybeSources + * a {@code MaybeSource} to be merged + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} * @see ReactiveX operators documentation: Merge */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable mergeDelayError(@NonNull MaybeSource source1, + public static <@NonNull T> Flowable mergeDelayError(@NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull MaybeSource source3) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); @@ -1537,19 +1911,19 @@ public static Flowable mergeDelayError(@NonNull MaybeSource } /** - * Flattens four MaybeSources into one Flowable, in a way that allows a Subscriber to receive all - * successfully emitted items from all of the source MaybeSources without being interrupted by an error + * Flattens four {@link MaybeSource}s into one {@link Flowable}, in a way that allows a subscriber to receive all + * successfully emitted items from all of the source {@code MaybeSource}s without being interrupted by an error * notification from one of them. *

+ * + *

* This behaves like {@link #merge(MaybeSource, MaybeSource, MaybeSource, MaybeSource)} except that if any of - * the merged MaybeSources notify of an error via {@link Subscriber#onError onError}, {@code mergeDelayError} - * will refrain from propagating that error notification until all of the merged MaybeSources have finished + * the merged {@code MaybeSource}s notify of an error via {@link Subscriber#onError onError}, {@code mergeDelayError} + * will refrain from propagating that error notification until all of the merged {@code MaybeSource}s have finished * emitting items. *

- * - *

- * Even if multiple merged MaybeSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Subscribers once. + * Even if multiple merged {@code MaybeSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its subscribers once. *

*
Backpressure:
*
The operator honors backpressure from downstream.
@@ -1559,21 +1933,22 @@ public static Flowable mergeDelayError(@NonNull MaybeSource * * @param the common element base type * @param source1 - * a MaybeSource to be merged + * a {@code MaybeSource} to be merged * @param source2 - * a MaybeSource to be merged + * a {@code MaybeSource} to be merged * @param source3 - * a MaybeSource to be merged + * a {@code MaybeSource} to be merged * @param source4 - * a MaybeSource to be merged - * @return a Flowable that emits all of the items that are emitted by the source MaybeSources + * a {@code MaybeSource} to be merged + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} * @see ReactiveX operators documentation: Merge */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable mergeDelayError( + public static <@NonNull T> Flowable mergeDelayError( @NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull MaybeSource source3, @NonNull MaybeSource source4) { Objects.requireNonNull(source1, "source1 is null"); @@ -1584,82 +1959,83 @@ public static Flowable mergeDelayError( } /** - * Returns a Maybe that never sends any items or notifications to a {@link MaybeObserver}. + * Returns a {@code Maybe} that never sends any items or notifications to a {@link MaybeObserver}. *

- * + * *

- * This Maybe is useful primarily for testing purposes. + * This {@code Maybe} is useful primarily for testing purposes. *

*
Scheduler:
*
{@code never} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items (not) emitted by the Maybe - * @return a Maybe that never emits any items or sends any notifications to a {@link MaybeObserver} + * the type of items (not) emitted by the {@code Maybe} + * @return the shared {@code Maybe} instance * @see ReactiveX operators documentation: Never */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @SuppressWarnings("unchecked") @NonNull - public static Maybe never() { + public static <@NonNull T> Maybe never() { return RxJavaPlugins.onAssembly((Maybe)MaybeNever.INSTANCE); } /** - * Returns a Single that emits a Boolean value that indicates whether two MaybeSource sequences are the - * same by comparing the items emitted by each MaybeSource pairwise. + * Returns a {@link Single} that emits a {@link Boolean} value that indicates whether two {@link MaybeSource} sequences are the + * same by comparing the items emitted by each {@code MaybeSource} pairwise. *

- * + * *

*
Scheduler:
*
{@code sequenceEqual} does not operate by default on a particular {@link Scheduler}.
*
* * @param source1 - * the first MaybeSource to compare + * the first {@code MaybeSource} to compare * @param source2 - * the second MaybeSource to compare + * the second {@code MaybeSource} to compare * @param - * the type of items emitted by each MaybeSource - * @return a Single that emits a Boolean value that indicates whether the two sequences are the same + * the type of items emitted by each {@code MaybeSource} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @see ReactiveX operators documentation: SequenceEqual */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Single sequenceEqual(@NonNull MaybeSource source1, @NonNull MaybeSource source2) { + public static <@NonNull T> Single sequenceEqual(@NonNull MaybeSource source1, @NonNull MaybeSource source2) { return sequenceEqual(source1, source2, ObjectHelper.equalsPredicate()); } /** - * Returns a Single that emits a Boolean value that indicates whether two MaybeSources are the - * same by comparing the items emitted by each MaybeSource pairwise based on the results of a specified + * Returns a {@link Single} that emits a {@link Boolean} value that indicates whether two {@link MaybeSource}s are the + * same by comparing the items emitted by each {@code MaybeSource} pairwise based on the results of a specified * equality function. *

- * + * *

*
Scheduler:
*
{@code sequenceEqual} does not operate by default on a particular {@link Scheduler}.
*
* * @param source1 - * the first MaybeSource to compare + * the first {@code MaybeSource} to compare * @param source2 - * the second MaybeSource to compare + * the second {@code MaybeSource} to compare * @param isEqual - * a function used to compare items emitted by each MaybeSource + * a function used to compare items emitted by each {@code MaybeSource} * @param - * the type of items emitted by each MaybeSource - * @return a Single that emits a Boolean value that indicates whether the two MaybeSource sequences - * are the same according to the specified function + * the type of items emitted by each {@code MaybeSource} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code isEqual} is {@code null} * @see ReactiveX operators documentation: SequenceEqual */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single sequenceEqual(@NonNull MaybeSource source1, @NonNull MaybeSource source2, + public static <@NonNull T> Single sequenceEqual(@NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull BiPredicate isEqual) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); @@ -1668,19 +2044,89 @@ public static Single sequenceEqual(@NonNull MaybeSource - * + * *
+ *
Backpressure:
+ *
The {@code sources} {@code Publisher} is consumed in an unbounded manner (requesting {@link Long#MAX_VALUE}). + * The returned {@code Flowable} respects the backpressure from the downstream.
*
Scheduler:
- *
{@code timer} operates by default on the {@code computation} {@link Scheduler}.
- *
- * - * @param delay - * the initial delay before emitting a single {@code 0L} - * @param unit - * time units to use for {@code delay} - * @return a Maybe that emits {@code 0L} after a specified delay + *
{@code switchOnNext} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
The returned sequence fails with the first error signaled by the {@code sources} {@code Publisher} + * or the currently running {@code MaybeSource}, disposing the rest. Late errors are + * forwarded to the global error handler via {@link RxJavaPlugins#onError(Throwable)}.
+ *
+ * @param the element type of the {@code MaybeSource}s + * @param sources the {@code Publisher} sequence of inner {@code MaybeSource}s to switch between + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + * @see #switchOnNextDelayError(Publisher) + * @see ReactiveX operators documentation: Switch + */ + @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Flowable switchOnNext(@NonNull Publisher<@NonNull ? extends MaybeSource> sources) { + Objects.requireNonNull(sources, "sources is null"); + return RxJavaPlugins.onAssembly(new FlowableSwitchMapMaybePublisher<>(sources, Functions.identity(), false)); + } + + /** + * Switches between {@link MaybeSource}s emitted by the source {@link Publisher} whenever + * a new {@code MaybeSource} is emitted, disposing the previously running {@code MaybeSource}, + * exposing the success items as a {@link Flowable} sequence and delaying all errors from + * all of them until all terminate. + *

+ * + *

+ *
Backpressure:
+ *
The {@code sources} {@code Publisher} is consumed in an unbounded manner (requesting {@link Long#MAX_VALUE}). + * The returned {@code Flowable} respects the backpressure from the downstream.
+ *
Scheduler:
+ *
{@code switchOnNextDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
The returned {@code Flowable} collects all errors emitted by either the {@code sources} + * {@code Publisher} or any inner {@code MaybeSource} and emits them as a {@link CompositeException} + * when all sources terminate. If only one source ever failed, its error is emitted as-is at the end.
+ *
+ * @param the element type of the {@code MaybeSource}s + * @param sources the {@code Publisher} sequence of inner {@code MaybeSource}s to switch between + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + * @see #switchOnNext(Publisher) + * @see ReactiveX operators documentation: Switch + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Flowable switchOnNextDelayError(@NonNull Publisher<@NonNull ? extends MaybeSource> sources) { + Objects.requireNonNull(sources, "sources is null"); + return RxJavaPlugins.onAssembly(new FlowableSwitchMapMaybePublisher<>(sources, Functions.identity(), true)); + } + + /** + * Returns a {@code Maybe} that emits {@code 0L} after a specified delay. + *

+ * + *

+ *
Scheduler:
+ *
{@code timer} operates by default on the {@code computation} {@link Scheduler}.
+ *
+ * + * @param delay + * the initial delay before emitting a single {@code 0L} + * @param unit + * time units to use for {@code delay} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Timer */ @CheckReturnValue @@ -1691,12 +2137,12 @@ public static Maybe timer(long delay, @NonNull TimeUnit unit) { } /** - * Returns a Maybe that emits {@code 0L} after a specified delay on a specified Scheduler. + * Returns a {@code Maybe} that emits {@code 0L} after a specified delay on a specified {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param delay @@ -1704,8 +2150,9 @@ public static Maybe timer(long delay, @NonNull TimeUnit unit) { * @param unit * time units to use for {@code delay} * @param scheduler - * the {@link Scheduler} to use for scheduling the item - * @return a Maybe that emits {@code 0L} after a specified delay, on a specified Scheduler + * the {@code Scheduler} to use for scheduling the item + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Timer */ @CheckReturnValue @@ -1719,20 +2166,24 @@ public static Maybe timer(long delay, @NonNull TimeUnit unit, @NonNull Sch } /** - * Advanced use only: creates a Maybe instance without - * any safeguards by using a callback that is called with a MaybeObserver. + * Advanced use only: creates a {@code Maybe} instance without + * any safeguards by using a callback that is called with a {@link MaybeObserver}. + *

+ * *

*
Scheduler:
*
{@code unsafeCreate} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param onSubscribe the function that is called with the subscribing MaybeObserver - * @return the new Maybe instance + * @param onSubscribe the function that is called with the subscribing {@code MaybeObserver} + * @return the new {@code Maybe} instance + * @throws IllegalArgumentException if {@code onSubscribe} is a {@code Maybe} + * @throws NullPointerException if {@code onSubscribe} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe unsafeCreate(@NonNull MaybeSource onSubscribe) { + public static <@NonNull T> Maybe unsafeCreate(@NonNull MaybeSource onSubscribe) { if (onSubscribe instanceof Maybe) { throw new IllegalArgumentException("unsafeCreate(Maybe) should be upgraded"); } @@ -1741,91 +2192,96 @@ public static Maybe unsafeCreate(@NonNull MaybeSource onSubscribe) { } /** - * Constructs a Maybe that creates a dependent resource object which is disposed of when the - * upstream terminates or the downstream calls dispose(). + * Constructs a {@code Maybe} that creates a dependent resource object which is disposed of when the + * generated {@link MaybeSource} terminates or the downstream calls dispose(). *

- * + * *

*
Scheduler:
*
{@code using} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the element type of the generated MaybeSource + * @param the element type of the generated {@code MaybeSource} * @param the type of the resource associated with the output sequence * @param resourceSupplier - * the factory function to create a resource object that depends on the Maybe + * the factory function to create a resource object that depends on the {@code Maybe} * @param sourceSupplier - * the factory function to create a MaybeSource - * @param resourceDisposer + * the factory function to create a {@code MaybeSource} + * @param resourceCleanup * the function that will dispose of the resource - * @return the Maybe whose lifetime controls the lifetime of the dependent resource object + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code resourceSupplier}, {@code sourceSupplier} or {@code resourceCleanup} is {@code null} * @see ReactiveX operators documentation: Using */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Maybe using(@NonNull Supplier resourceSupplier, + public static <@NonNull T, @NonNull D> Maybe using(@NonNull Supplier resourceSupplier, @NonNull Function> sourceSupplier, - @NonNull Consumer resourceDisposer) { - return using(resourceSupplier, sourceSupplier, resourceDisposer, true); + @NonNull Consumer resourceCleanup) { + return using(resourceSupplier, sourceSupplier, resourceCleanup, true); } /** - * Constructs a Maybe that creates a dependent resource object which is disposed of just before - * termination if you have set {@code disposeEagerly} to {@code true} and a downstream dispose() does not occur - * before termination. Otherwise resource disposal will occur on call to dispose(). Eager disposal is - * particularly appropriate for a synchronous Maybe that reuses resources. {@code disposeAction} will - * only be called once per subscription. + * Constructs a {@code Maybe} that creates a dependent resource object which is disposed first ({code eager == true}) + * when the generated {@link MaybeSource} terminates or the downstream disposes; or after ({code eager == false}). *

- * + * + *

+ * Eager disposal is particularly appropriate for a synchronous {@code Maybe} that reuses resources. {@code disposeAction} will + * only be called once per subscription. *

*
Scheduler:
*
{@code using} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the element type of the generated MaybeSource + * @param the element type of the generated {@code MaybeSource} * @param the type of the resource associated with the output sequence * @param resourceSupplier - * the factory function to create a resource object that depends on the Maybe + * the factory function to create a resource object that depends on the {@code Maybe} * @param sourceSupplier - * the factory function to create a MaybeSource - * @param resourceDisposer + * the factory function to create a {@code MaybeSource} + * @param resourceCleanup * the function that will dispose of the resource * @param eager * If {@code true} then resource disposal will happen either on a {@code dispose()} call before the upstream is disposed * or just before the emission of a terminal event ({@code onSuccess}, {@code onComplete} or {@code onError}). * If {@code false} the resource disposal will happen either on a {@code dispose()} call after the upstream is disposed * or just after the emission of a terminal event ({@code onSuccess}, {@code onComplete} or {@code onError}). - * @return the Maybe whose lifetime controls the lifetime of the dependent resource object + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code resourceSupplier}, {@code sourceSupplier} or {@code resourceCleanup} is {@code null} * @see ReactiveX operators documentation: Using */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe using(@NonNull Supplier resourceSupplier, + public static <@NonNull T, @NonNull D> Maybe using(@NonNull Supplier resourceSupplier, @NonNull Function> sourceSupplier, - @NonNull Consumer resourceDisposer, boolean eager) { + @NonNull Consumer resourceCleanup, boolean eager) { Objects.requireNonNull(resourceSupplier, "resourceSupplier is null"); Objects.requireNonNull(sourceSupplier, "sourceSupplier is null"); - Objects.requireNonNull(resourceDisposer, "resourceDisposer is null"); - return RxJavaPlugins.onAssembly(new MaybeUsing(resourceSupplier, sourceSupplier, resourceDisposer, eager)); + Objects.requireNonNull(resourceCleanup, "resourceCleanup is null"); + return RxJavaPlugins.onAssembly(new MaybeUsing(resourceSupplier, sourceSupplier, resourceCleanup, eager)); } /** - * Wraps a MaybeSource instance into a new Maybe instance if not already a Maybe + * Wraps a {@link MaybeSource} instance into a new {@code Maybe} instance if not already a {@code Maybe} * instance. + *

+ * *

*
Scheduler:
*
{@code wrap} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type * @param source the source to wrap - * @return the Maybe wrapper or the source cast to Maybe (if possible) + * @return the new wrapped or cast {@code Maybe} instance + * @throws NullPointerException if {@code source} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe wrap(@NonNull MaybeSource source) { + public static <@NonNull T> Maybe wrap(@NonNull MaybeSource source) { if (source instanceof Maybe) { return RxJavaPlugins.onAssembly((Maybe)source); } @@ -1834,16 +2290,16 @@ public static Maybe wrap(@NonNull MaybeSource source) { } /** - * Returns a Maybe that emits the results of a specified combiner function applied to combinations of - * items emitted, in sequence, by an Iterable of other MaybeSources. + * Returns a {@code Maybe} that emits the results of a specified combiner function applied to combinations of + * items emitted, in sequence, by an {@link Iterable} of other {@link MaybeSource}s. *

* *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. *

- * This operator terminates eagerly if any of the source MaybeSources signal an onError or onComplete. This + * This operator terminates eagerly if any of the source {@code MaybeSource}s signal an {@code onError} or {@code onComplete}. This * also means it is possible some sources may not get subscribed to at all. *

*
Scheduler:
@@ -1853,29 +2309,30 @@ public static Maybe wrap(@NonNull MaybeSource source) { * @param the common value type * @param the zipped result type * @param sources - * an Iterable of source MaybeSources + * an {@code Iterable} of source {@code MaybeSource}s * @param zipper - * a function that, when applied to an item emitted by each of the source MaybeSources, results in - * an item that will be emitted by the resulting Maybe - * @return a Maybe that emits the zipped results + * a function that, when applied to an item emitted by each of the source {@code MaybeSource}s, results in + * an item that will be emitted by the resulting {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code zipper} or {@code sources} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe zip(@NonNull Iterable> sources, @NonNull Function zipper) { + public static <@NonNull T, @NonNull R> Maybe zip(@NonNull Iterable<@NonNull ? extends MaybeSource> sources, @NonNull Function zipper) { Objects.requireNonNull(zipper, "zipper is null"); Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new MaybeZipIterable<>(sources, zipper)); } /** - * Returns a Maybe that emits the results of a specified combiner function applied to combinations of - * two items emitted, in sequence, by two other MaybeSources. + * Returns a {@code Maybe} that emits the results of a specified combiner function applied to combinations of + * two items emitted, in sequence, by two other {@link MaybeSource}s. *

* *

- * This operator terminates eagerly if any of the source MaybeSources signal an onError or onComplete. This + * This operator terminates eagerly if any of the source {@code MaybeSource}s signal an {@code onError} or {@code onComplete}. This * also means it is possible some sources may not get subscribed to at all. *

*
Scheduler:
@@ -1886,19 +2343,20 @@ public static Maybe zip(@NonNull Iterable the value type of the second source * @param the zipped result type * @param source1 - * the first source MaybeSource + * the first source {@code MaybeSource} * @param source2 - * a second source MaybeSource + * a second source {@code MaybeSource} * @param zipper - * a function that, when applied to an item emitted by each of the source MaybeSources, results - * in an item that will be emitted by the resulting Maybe - * @return a Maybe that emits the zipped results + * a function that, when applied to an item emitted by each of the source {@code MaybeSource}s, results + * in an item that will be emitted by the resulting {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe zip( + public static <@NonNull T1, @NonNull T2, @NonNull R> Maybe zip( @NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull BiFunction zipper) { Objects.requireNonNull(source1, "source1 is null"); @@ -1908,12 +2366,12 @@ public static Maybe zip( } /** - * Returns a Maybe that emits the results of a specified combiner function applied to combinations of - * three items emitted, in sequence, by three other MaybeSources. + * Returns a {@code Maybe} that emits the results of a specified combiner function applied to combinations of + * three items emitted, in sequence, by three other {@link MaybeSource}s. *

* *

- * This operator terminates eagerly if any of the source MaybeSources signal an onError or onComplete. This + * This operator terminates eagerly if any of the source {@code MaybeSource}s signal an {@code onError} or {@code onComplete}. This * also means it is possible some sources may not get subscribed to at all. *

*
Scheduler:
@@ -1925,21 +2383,22 @@ public static Maybe zip( * @param the value type of the third source * @param the zipped result type * @param source1 - * the first source MaybeSource + * the first source {@code MaybeSource} * @param source2 - * a second source MaybeSource + * a second source {@code MaybeSource} * @param source3 - * a third source MaybeSource + * a third source {@code MaybeSource} * @param zipper - * a function that, when applied to an item emitted by each of the source MaybeSources, results in - * an item that will be emitted by the resulting Maybe - * @return a Maybe that emits the zipped results + * a function that, when applied to an item emitted by each of the source {@code MaybeSource}s, results in + * an item that will be emitted by the resulting {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull R> Maybe zip( @NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull MaybeSource source3, @NonNull Function3 zipper) { Objects.requireNonNull(source1, "source1 is null"); @@ -1950,12 +2409,12 @@ public static Maybe zip( } /** - * Returns a Maybe that emits the results of a specified combiner function applied to combinations of - * four items emitted, in sequence, by four other MaybeSources. + * Returns a {@code Maybe} that emits the results of a specified combiner function applied to combinations of + * four items emitted, in sequence, by four other {@link MaybeSource}s. *

* *

- * This operator terminates eagerly if any of the source MaybeSources signal an onError or onComplete. This + * This operator terminates eagerly if any of the source {@code MaybeSource}s signal an {@code onError} or {@code onComplete}. This * also means it is possible some sources may not get subscribed to at all. *

*
Scheduler:
@@ -1968,23 +2427,25 @@ public static Maybe zip( * @param the value type of the fourth source * @param the zipped result type * @param source1 - * the first source MaybeSource + * the first source {@code MaybeSource} * @param source2 - * a second source MaybeSource + * a second source {@code MaybeSource} * @param source3 - * a third source MaybeSource + * a third source {@code MaybeSource} * @param source4 - * a fourth source MaybeSource + * a fourth source {@code MaybeSource} * @param zipper - * a function that, when applied to an item emitted by each of the source MaybeSources, results in - * an item that will be emitted by the resulting Maybe - * @return a Maybe that emits the zipped results + * a function that, when applied to an item emitted by each of the source {@code MaybeSource}s, results in + * an item that will be emitted by the resulting {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull R> Maybe zip( @NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull MaybeSource source3, @NonNull MaybeSource source4, @NonNull Function4 zipper) { @@ -1997,12 +2458,12 @@ public static Maybe zip( } /** - * Returns a Maybe that emits the results of a specified combiner function applied to combinations of - * five items emitted, in sequence, by five other MaybeSources. + * Returns a {@code Maybe} that emits the results of a specified combiner function applied to combinations of + * five items emitted, in sequence, by five other {@link MaybeSource}s. *

* *

- * This operator terminates eagerly if any of the source MaybeSources signal an onError or onComplete. This + * This operator terminates eagerly if any of the source {@code MaybeSource}s signal an {@code onError} or {@code onComplete}. This * also means it is possible some sources may not get subscribed to at all. *

*
Scheduler:
@@ -2016,25 +2477,27 @@ public static Maybe zip( * @param the value type of the fifth source * @param the zipped result type * @param source1 - * the first source MaybeSource + * the first source {@code MaybeSource} * @param source2 - * a second source MaybeSource + * a second source {@code MaybeSource} * @param source3 - * a third source MaybeSource + * a third source {@code MaybeSource} * @param source4 - * a fourth source MaybeSource + * a fourth source {@code MaybeSource} * @param source5 - * a fifth source MaybeSource + * a fifth source {@code MaybeSource} * @param zipper - * a function that, when applied to an item emitted by each of the source MaybeSources, results in - * an item that will be emitted by the resulting Maybe - * @return a Maybe that emits the zipped results + * a function that, when applied to an item emitted by each of the source {@code MaybeSource}s, results in + * an item that will be emitted by the resulting {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull R> Maybe zip( @NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull MaybeSource source3, @NonNull MaybeSource source4, @NonNull MaybeSource source5, @NonNull Function5 zipper) { @@ -2048,12 +2511,12 @@ public static Maybe zip( } /** - * Returns a Maybe that emits the results of a specified combiner function applied to combinations of - * six items emitted, in sequence, by six other MaybeSources. + * Returns a {@code Maybe} that emits the results of a specified combiner function applied to combinations of + * six items emitted, in sequence, by six other {@link MaybeSource}s. *

* *

- * This operator terminates eagerly if any of the source MaybeSources signal an onError or onComplete. This + * This operator terminates eagerly if any of the source {@code MaybeSource}s signal an {@code onError} or {@code onComplete}. This * also means it is possible some sources may not get subscribed to at all. *

*
Scheduler:
@@ -2068,27 +2531,29 @@ public static Maybe zip( * @param the value type of the sixth source * @param the zipped result type * @param source1 - * the first source MaybeSource + * the first source {@code MaybeSource} * @param source2 - * a second source MaybeSource + * a second source {@code MaybeSource} * @param source3 - * a third source MaybeSource + * a third source {@code MaybeSource} * @param source4 - * a fourth source MaybeSource + * a fourth source {@code MaybeSource} * @param source5 - * a fifth source MaybeSource + * a fifth source {@code MaybeSource} * @param source6 - * a sixth source MaybeSource + * a sixth source {@code MaybeSource} * @param zipper - * a function that, when applied to an item emitted by each of the source MaybeSources, results in - * an item that will be emitted by the resulting Maybe - * @return a Maybe that emits the zipped results + * a function that, when applied to an item emitted by each of the source {@code MaybeSource}s, results in + * an item that will be emitted by the resulting {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull R> Maybe zip( @NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull MaybeSource source3, @NonNull MaybeSource source4, @NonNull MaybeSource source5, @NonNull MaybeSource source6, @NonNull Function6 zipper) { @@ -2103,12 +2568,12 @@ public static Maybe zip( } /** - * Returns a Maybe that emits the results of a specified combiner function applied to combinations of - * seven items emitted, in sequence, by seven other MaybeSources. + * Returns a {@code Maybe} that emits the results of a specified combiner function applied to combinations of + * seven items emitted, in sequence, by seven other {@link MaybeSource}s. *

* *

- * This operator terminates eagerly if any of the source MaybeSources signal an onError or onComplete. This + * This operator terminates eagerly if any of the source {@code MaybeSource}s signal an {@code onError} or {@code onComplete}. This * also means it is possible some sources may not get subscribed to at all. *

*
Scheduler:
@@ -2124,29 +2589,32 @@ public static Maybe zip( * @param the value type of the seventh source * @param the zipped result type * @param source1 - * the first source MaybeSource + * the first source {@code MaybeSource} * @param source2 - * a second source MaybeSource + * a second source {@code MaybeSource} * @param source3 - * a third source MaybeSource + * a third source {@code MaybeSource} * @param source4 - * a fourth source MaybeSource + * a fourth source {@code MaybeSource} * @param source5 - * a fifth source MaybeSource + * a fifth source {@code MaybeSource} * @param source6 - * a sixth source MaybeSource + * a sixth source {@code MaybeSource} * @param source7 - * a seventh source MaybeSource + * a seventh source {@code MaybeSource} * @param zipper - * a function that, when applied to an item emitted by each of the source MaybeSources, results in - * an item that will be emitted by the resulting Maybe - * @return a Maybe that emits the zipped results + * a function that, when applied to an item emitted by each of the source {@code MaybeSource}s, results in + * an item that will be emitted by the resulting {@code Maybe} + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7} or {@code zipper} is {@code null} + * @return the new {@code Maybe} instance * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull R> Maybe zip( @NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull MaybeSource source3, @NonNull MaybeSource source4, @NonNull MaybeSource source5, @NonNull MaybeSource source6, @NonNull MaybeSource source7, @@ -2163,12 +2631,12 @@ public static Maybe zip( } /** - * Returns a Maybe that emits the results of a specified combiner function applied to combinations of - * eight items emitted, in sequence, by eight other MaybeSources. + * Returns a {@code Maybe} that emits the results of a specified combiner function applied to combinations of + * eight items emitted, in sequence, by eight other {@link MaybeSource}s. *

* *

- * This operator terminates eagerly if any of the source MaybeSources signal an onError or onComplete. This + * This operator terminates eagerly if any of the source {@code MaybeSource}s signal an {@code onError} or {@code onComplete}. This * also means it is possible some sources may not get subscribed to at all. *

*
Scheduler:
@@ -2185,31 +2653,34 @@ public static Maybe zip( * @param the value type of the eighth source * @param the zipped result type * @param source1 - * the first source MaybeSource + * the first source {@code MaybeSource} * @param source2 - * a second source MaybeSource + * a second source {@code MaybeSource} * @param source3 - * a third source MaybeSource + * a third source {@code MaybeSource} * @param source4 - * a fourth source MaybeSource + * a fourth source {@code MaybeSource} * @param source5 - * a fifth source MaybeSource + * a fifth source {@code MaybeSource} * @param source6 - * a sixth source MaybeSource + * a sixth source {@code MaybeSource} * @param source7 - * a seventh source MaybeSource + * a seventh source {@code MaybeSource} * @param source8 - * an eighth source MaybeSource + * an eighth source {@code MaybeSource} * @param zipper - * a function that, when applied to an item emitted by each of the source MaybeSources, results in - * an item that will be emitted by the resulting Maybe - * @return a Maybe that emits the zipped results + * a function that, when applied to an item emitted by each of the source {@code MaybeSource}s, results in + * an item that will be emitted by the resulting {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7}, {@code source8} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull R> Maybe zip( @NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull MaybeSource source3, @NonNull MaybeSource source4, @NonNull MaybeSource source5, @NonNull MaybeSource source6, @NonNull MaybeSource source7, @NonNull MaybeSource source8, @@ -2227,12 +2698,12 @@ public static Maybe zip( } /** - * Returns a Maybe that emits the results of a specified combiner function applied to combinations of - * nine items emitted, in sequence, by nine other MaybeSources. + * Returns a {@code Maybe} that emits the results of a specified combiner function applied to combinations of + * nine items emitted, in sequence, by nine other {@link MaybeSource}s. *

* *

- * This operator terminates eagerly if any of the source MaybeSources signal an onError or onComplete. This + * This operator terminates eagerly if any of the source {@code MaybeSource}s signal an {@code onError} or {@code onComplete}. This * also means it is possible some sources may not get subscribed to at all. *

*
Scheduler:
@@ -2249,33 +2720,36 @@ public static Maybe zip( * @param the value type of the ninth source * @param the zipped result type * @param source1 - * the first source MaybeSource + * the first source {@code MaybeSource} * @param source2 - * a second source MaybeSource + * a second source {@code MaybeSource} * @param source3 - * a third source MaybeSource + * a third source {@code MaybeSource} * @param source4 - * a fourth source MaybeSource + * a fourth source {@code MaybeSource} * @param source5 - * a fifth source MaybeSource + * a fifth source {@code MaybeSource} * @param source6 - * a sixth source MaybeSource + * a sixth source {@code MaybeSource} * @param source7 - * a seventh source MaybeSource + * a seventh source {@code MaybeSource} * @param source8 - * an eighth source MaybeSource + * an eighth source {@code MaybeSource} * @param source9 - * a ninth source MaybeSource + * a ninth source {@code MaybeSource} * @param zipper - * a function that, when applied to an item emitted by each of the source MaybeSources, results in - * an item that will be emitted by the resulting MaybeSource - * @return a Maybe that emits the zipped results + * a function that, when applied to an item emitted by each of the source {@code MaybeSource}s, results in + * an item that will be emitted by the resulting {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7}, {@code source8}, {@code source9} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Maybe zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull T9, @NonNull R> Maybe zip( @NonNull MaybeSource source1, @NonNull MaybeSource source2, @NonNull MaybeSource source3, @NonNull MaybeSource source4, @NonNull MaybeSource source5, @NonNull MaybeSource source6, @NonNull MaybeSource source7, @NonNull MaybeSource source8, @NonNull MaybeSource source9, @@ -2295,16 +2769,16 @@ public static Maybe zip( } /** - * Returns a Maybe that emits the results of a specified combiner function applied to combinations of - * items emitted, in sequence, by an array of other MaybeSources. + * Returns a {@code Maybe} that emits the results of a specified combiner function applied to combinations of + * items emitted, in sequence, by an array of other {@link MaybeSource}s. *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. * *

- * - *

This operator terminates eagerly if any of the source MaybeSources signal an onError or onComplete. This + * + *

This operator terminates eagerly if any of the source {@code MaybeSource}s signal an {@code onError} or {@code onComplete}. This * also means it is possible some sources may not get subscribed to at all. *

*
Scheduler:
@@ -2314,18 +2788,19 @@ public static Maybe zip( * @param the common element type * @param the result type * @param sources - * an array of source MaybeSources + * an array of source {@code MaybeSource}s * @param zipper - * a function that, when applied to an item emitted by each of the source MaybeSources, results in - * an item that will be emitted by the resulting MaybeSource - * @return a Maybe that emits the zipped results + * a function that, when applied to an item emitted by each of the source {@code MaybeSource}s, results in + * an item that will be emitted by the resulting {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code sources} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs - public static Maybe zipArray(@NonNull Function zipper, + public static <@NonNull T, @NonNull R> Maybe zipArray(@NonNull Function zipper, @NonNull MaybeSource... sources) { Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { @@ -2340,19 +2815,19 @@ public static Maybe zipArray(@NonNull Function - * + * *
*
Scheduler:
*
{@code ambWith} does not operate by default on a particular {@link Scheduler}.
*
* * @param other - * a MaybeSource competing to react first. A subscription to this provided source will occur after + * a {@code MaybeSource} competing to react first. A subscription to this provided source will occur after * subscribing to the current source. - * @return a Maybe that emits the same sequence as whichever of the source MaybeSources first - * signalled + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: Amb */ @CheckReturnValue @@ -2364,8 +2839,10 @@ public final Maybe ambWith(@NonNull MaybeSource other) { } /** - * Waits in a blocking fashion until the current Maybe signals a success value (which is returned), - * null if completed or an exception (which is propagated). + * Waits in a blocking fashion until the current {@code Maybe} signals a success value (which is returned), + * {@code null} if completed or an exception (which is propagated). + *

+ * *

*
Scheduler:
*
{@code blockingGet} does not operate by default on a particular {@link Scheduler}.
@@ -2386,8 +2863,10 @@ public final T blockingGet() { } /** - * Waits in a blocking fashion until the current Maybe signals a success value (which is returned), + * Waits in a blocking fashion until the current {@code Maybe} signals a success value (which is returned), * defaultValue if completed or an exception (which is propagated). + *

+ * *

*
Scheduler:
*
{@code blockingGet} does not operate by default on a particular {@link Scheduler}.
@@ -2396,13 +2875,14 @@ public final T blockingGet() { * into {@link RuntimeException} and throws that. Otherwise, {@code RuntimeException}s and * {@link Error}s are rethrown as they are.
*
- * @param defaultValue the default item to return if this Maybe is empty + * @param defaultValue the default item to return if this {@code Maybe} is empty * @return the success value + * @throws NullPointerException if {@code defaultValue} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) - @Nullable - public final T blockingGet(@Nullable T defaultValue) { + @NonNull + public final T blockingGet(@NonNull T defaultValue) { Objects.requireNonNull(defaultValue, "defaultValue is null"); BlockingMultiObserver observer = new BlockingMultiObserver<>(); subscribe(observer); @@ -2410,13 +2890,142 @@ public final T blockingGet(@Nullable T defaultValue) { } /** - * Returns a Maybe that subscribes to this Maybe lazily, caches its event + * Subscribes to the current {@code Maybe} and blocks the current thread until it terminates. + *

+ * + *

+ *
Scheduler:
+ *
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If the current {@code Maybe} signals an error, + * the {@link Throwable} is routed to the global error handler via {@link RxJavaPlugins#onError(Throwable)}. + * If the current thread is interrupted, an {@link InterruptedException} is routed to the same global error handler. + *
+ *
+ * @since 3.0.0 + * @see #blockingSubscribe(Consumer) + * @see #blockingSubscribe(Consumer, Consumer) + * @see #blockingSubscribe(Consumer, Consumer, Action) + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void blockingSubscribe() { + blockingSubscribe(Functions.emptyConsumer(), Functions.ERROR_CONSUMER, Functions.EMPTY_ACTION); + } + + /** + * Subscribes to the current {@code Maybe} and calls given {@code onSuccess} callback on the current thread + * when it completes normally. + *

+ * + *

+ *
Scheduler:
+ *
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If either the current {@code Maybe} signals an error or {@code onSuccess} throws, + * the respective {@link Throwable} is routed to the global error handler via {@link RxJavaPlugins#onError(Throwable)}. + * If the current thread is interrupted, an {@link InterruptedException} is routed to the same global error handler. + *
+ *
+ * @param onSuccess the {@link Consumer} to call if the current {@code Maybe} succeeds + * @throws NullPointerException if {@code onSuccess} is {@code null} + * @since 3.0.0 + * @see #blockingSubscribe(Consumer, Consumer) + * @see #blockingSubscribe(Consumer, Consumer, Action) + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void blockingSubscribe(@NonNull Consumer onSuccess) { + blockingSubscribe(onSuccess, Functions.ERROR_CONSUMER, Functions.EMPTY_ACTION); + } + + /** + * Subscribes to the current {@code Maybe} and calls the appropriate callback on the current thread + * when it terminates. + *

+ * + *

+ *
Scheduler:
+ *
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If either {@code onSuccess} or {@code onError} throw, the {@link Throwable} is routed to the + * global error handler via {@link RxJavaPlugins#onError(Throwable)}. + * If the current thread is interrupted, the {@code onError} consumer is called with an {@link InterruptedException}. + *
+ *
+ * @param onSuccess the {@link Consumer} to call if the current {@code Maybe} succeeds + * @param onError the {@code Consumer} to call if the current {@code Maybe} signals an error + * @throws NullPointerException if {@code onSuccess} or {@code onError} is {@code null} + * @since 3.0.0 + * @see #blockingSubscribe(Consumer, Consumer, Action) + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void blockingSubscribe(@NonNull Consumer onSuccess, @NonNull Consumer onError) { + blockingSubscribe(onSuccess, onError, Functions.EMPTY_ACTION); + } + + /** + * Subscribes to the current {@code Maybe} and calls the appropriate callback on the current thread + * when it terminates. + *

+ * + *

+ *
Scheduler:
+ *
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If either {@code onSuccess}, {@code onError} or {@code onComplete} throw, the {@link Throwable} is routed to the + * global error handler via {@link RxJavaPlugins#onError(Throwable)}. + * If the current thread is interrupted, the {@code onError} consumer is called with an {@link InterruptedException}. + *
+ *
+ * @param onSuccess the {@link Consumer} to call if the current {@code Maybe} succeeds + * @param onError the {@code Consumer} to call if the current {@code Maybe} signals an error + * @param onComplete the {@link Action} to call if the current {@code Maybe} completes without a value + * @throws NullPointerException if {@code onSuccess}, {@code onError} or {@code onComplete} is {@code null} + * @since 3.0.0 + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void blockingSubscribe(@NonNull Consumer onSuccess, @NonNull Consumer onError, @NonNull Action onComplete) { + Objects.requireNonNull(onSuccess, "onSuccess is null"); + Objects.requireNonNull(onError, "onError is null"); + Objects.requireNonNull(onComplete, "onComplete is null"); + BlockingMultiObserver observer = new BlockingMultiObserver<>(); + subscribe(observer); + observer.blockingConsume(onSuccess, onError, onComplete); + } + + /** + * Subscribes to the current {@code Maybe} and calls the appropriate {@link MaybeObserver} method on the current thread. + *

+ * + *

+ *
Scheduler:
+ *
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
An {@code onError} signal is delivered to the {@link MaybeObserver#onError(Throwable)} method. + * If any of the {@code MaybeObserver}'s methods throw, the {@link RuntimeException} is propagated to the caller of this method. + * If the current thread is interrupted, an {@link InterruptedException} is delivered to {@code observer.onError}. + *
+ *
+ * @param observer the {@code MaybeObserver} to call methods on the current thread + * @throws NullPointerException if {@code observer} is {@code null} + * @since 3.0.0 + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void blockingSubscribe(@NonNull MaybeObserver observer) { + Objects.requireNonNull(observer, "observer is null"); + BlockingDisposableMultiObserver blockingObserver = new BlockingDisposableMultiObserver<>(); + observer.onSubscribe(blockingObserver); + subscribe(blockingObserver); + blockingObserver.blockingConsume(observer); + } + + /** + * Returns a {@code Maybe} that subscribes to this {@code Maybe} lazily, caches its event * and replays it, to all the downstream subscribers. *

- * + * *

* The operator subscribes only when the first downstream subscriber subscribes and maintains - * a single subscription towards this Maybe. + * a single subscription towards this {@code Maybe}. *

* Note: You sacrifice the ability to dispose the origin when you use the {@code cache}. *

@@ -2424,8 +3033,7 @@ public final T blockingGet(@Nullable T defaultValue) { *
{@code cache} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a Maybe that, when first subscribed to, caches all of its items and notifications for the - * benefit of subsequent subscribers + * @return the new {@code Maybe} instance * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @@ -2436,8 +3044,8 @@ public final Maybe cache() { } /** - * Casts the success value of the current Maybe into the target type or signals a - * ClassCastException if not compatible. + * Casts the success value of the current {@code Maybe} into the target type or signals a + * {@link ClassCastException} if not compatible. *

* *

@@ -2445,72 +3053,133 @@ public final Maybe cache() { *
{@code cast} does not operate by default on a particular {@link Scheduler}.
*
* @param the target type - * @param clazz the type token to use for casting the success result from the current Maybe - * @return the new Maybe instance + * @param clazz the type token to use for casting the success result from the current {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code clazz} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe cast(@NonNull Class clazz) { + public final <@NonNull U> Maybe cast(@NonNull Class clazz) { Objects.requireNonNull(clazz, "clazz is null"); return map(Functions.castFunction(clazz)); } /** - * Transform a Maybe by applying a particular Transformer function to it. + * Transform a {@code Maybe} by applying a particular {@link MaybeTransformer} function to it. + *

+ * *

- * This method operates on the Maybe itself whereas {@link #lift} operates on the Maybe's MaybeObservers. + * This method operates on the {@code Maybe} itself whereas {@link #lift} operates on the {@code Maybe}'s {@link MaybeObserver}s. *

- * If the operator you are creating is designed to act on the individual item emitted by a Maybe, use - * {@link #lift}. If your operator is designed to transform the source Maybe as a whole (for instance, by + * If the operator you are creating is designed to act on the individual item emitted by a {@code Maybe}, use + * {@link #lift}. If your operator is designed to transform the current {@code Maybe} as a whole (for instance, by * applying a particular set of existing RxJava operators to it) use {@code compose}. *

*
Scheduler:
*
{@code compose} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the value type of the Maybe returned by the transformer function - * @param transformer the transformer function, not null - * @return a Maybe, transformed by the transformer function + * @param the value type of the {@code Maybe} returned by the transformer function + * @param transformer the transformer function, not {@code null} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code transformer} is {@code null} * @see RxJava wiki: Implementing Your Own Operators */ @SuppressWarnings("unchecked") @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Maybe compose(@NonNull MaybeTransformer transformer) { + public final <@NonNull R> Maybe compose(@NonNull MaybeTransformer transformer) { return wrap(((MaybeTransformer) Objects.requireNonNull(transformer, "transformer is null")).apply(this)); } /** - * Returns a Maybe that is based on applying a specified function to the item emitted by the source Maybe, - * where that function returns a MaybeSource. + * Returns a {@code Maybe} that is based on applying a specified function to the item emitted by the current {@code Maybe}, + * where that function returns a {@link MaybeSource}. *

- * + * + *

+ * Note that flatMap and concatMap for {@code Maybe} is the same operation. *

*
Scheduler:
*
{@code concatMap} does not operate by default on a particular {@link Scheduler}.
*
- *

Note that flatMap and concatMap for Maybe is the same operation. * @param the result value type * @param mapper - * a function that, when applied to the item emitted by the source Maybe, returns a MaybeSource - * @return the Maybe returned from {@code func} when applied to the item emitted by the source Maybe + * a function that, when applied to the item emitted by the current {@code Maybe}, returns a {@code MaybeSource} + * @return the new {@code Maybe} instance * @see ReactiveX operators documentation: FlatMap + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe concatMap(@NonNull Function> mapper) { - Objects.requireNonNull(mapper, "mapper is null"); - return RxJavaPlugins.onAssembly(new MaybeFlatten<>(this, mapper)); + public final <@NonNull R> Maybe concatMap(@NonNull Function> mapper) { + return flatMap(mapper); } /** - * Returns a Flowable that emits the items emitted from the current MaybeSource, then the next, one after + * Returns a {@link Completable} that completes based on applying a specified function to the item emitted by the + * current {@code Maybe}, where that function returns a {@code Completable}. + *

+ * + *

+ * This operator is an alias for {@link #flatMapCompletable(Function)}. + *

+ *
Scheduler:
+ *
{@code concatMapCompletable} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param mapper + * a function that, when applied to the item emitted by the current {@code Maybe}, returns a + * {@code Completable} + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @see ReactiveX operators documentation: FlatMap + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final Completable concatMapCompletable(@NonNull Function mapper) { + return flatMapCompletable(mapper); + } + + /** + * Returns a {@code Maybe} based on applying a specified function to the item emitted by the + * current {@code Maybe}, where that function returns a {@link Single}. + * When this {@code Maybe} just completes the resulting {@code Maybe} completes as well. + *

+ * + *

+ * This operator is an alias for {@link #flatMapSingle(Function)}. + *

+ *
Scheduler:
+ *
{@code concatMapSingle} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param the result value type + * @param mapper + * a function that, when applied to the item emitted by the current {@code Maybe}, returns a + * {@code Single} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @see ReactiveX operators documentation: FlatMap + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final <@NonNull R> Maybe concatMapSingle(@NonNull Function> mapper) { + return flatMapSingle(mapper); + } + + /** + * Returns a {@link Flowable} that emits the items emitted from the current {@code Maybe}, then the {@code other} {@link MaybeSource}, one after * the other, without interleaving them. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from downstream.
@@ -2519,9 +3188,9 @@ public final Maybe concatMap(@NonNull Function * * @param other - * a MaybeSource to be concatenated after the current - * @return a Flowable that emits items emitted by the two source MaybeSources, one after the other, - * without interleaving them + * a {@code MaybeSource} to be concatenated after the current + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: Concat */ @BackpressureSupport(BackpressureKind.FULL) @@ -2534,7 +3203,7 @@ public final Flowable concatWith(@NonNull MaybeSource other) { } /** - * Returns a Single that emits a Boolean that indicates whether the source Maybe emitted a + * Returns a {@link Single} that emits a {@link Boolean} that indicates whether the current {@code Maybe} emitted a * specified item. *

* @@ -2544,9 +3213,9 @@ public final Flowable concatWith(@NonNull MaybeSource other) { *

* * @param item - * the item to search for in the emissions from the source Maybe, not null - * @return a Single that emits {@code true} if the specified item is emitted by the source Maybe, - * or {@code false} if the source Maybe completes without emitting that item + * the item to search for in the emissions from the current {@code Maybe}, not {@code null} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code item} is {@code null} * @see ReactiveX operators documentation: Contains */ @CheckReturnValue @@ -2558,17 +3227,16 @@ public final Single contains(@NonNull Object item) { } /** - * Returns a Single that counts the total number of items emitted (0 or 1) by the source Maybe and emits - * this count as a 64-bit Long. + * Returns a {@link Single} that counts the total number of items emitted (0 or 1) by the current {@code Maybe} and emits + * this count as a 64-bit {@link Long}. *

- * + * *

*
Scheduler:
*
{@code count} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a Single that emits a single item: the number of items emitted by the source Maybe as a - * 64-bit Long item + * @return the new {@code Single} instance * @see ReactiveX operators documentation: Count */ @CheckReturnValue @@ -2579,19 +3247,19 @@ public final Single count() { } /** - * Returns a Single that emits the item emitted by the source Maybe or a specified default item - * if the source Maybe is empty. + * Returns a {@link Single} that emits the item emitted by the current {@code Maybe} or a specified default item + * if the current {@code Maybe} is empty. *

- * + * *

*
Scheduler:
*
{@code defaultIfEmpty} does not operate by default on a particular {@link Scheduler}.
*
* * @param defaultItem - * the item to emit if the source Maybe emits no items - * @return a Single that emits either the specified default item if the source Maybe emits no - * item, or the item emitted by the source Maybe + * the item to emit if the current {@code Maybe} emits no items + * @return the new {@code Single} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX operators documentation: DefaultIfEmpty */ @CheckReturnValue @@ -2603,62 +3271,160 @@ public final Single defaultIfEmpty(@NonNull T defaultItem) { } /** - * Returns a Maybe that signals the events emitted by the source Maybe shifted forward in time by a + * Maps the {@link Notification} success value of the current {@code Maybe} back into normal + * {@code onSuccess}, {@code onError} or {@code onComplete} signals. + *

+ * + *

+ * The intended use of the {@code selector} function is to perform a + * type-safe identity mapping (see example) on a source that is already of type + * {@code Notification}. The Java language doesn't allow + * limiting instance methods to a certain generic argument shape, therefore, + * a function is used to ensure the conversion remains type safe. + *

+ * Regular {@code onError} or {@code onComplete} signals from the current {@code Maybe} are passed along to the downstream. + *

+ *
Scheduler:
+ *
{@code dematerialize} does not operate by default on a particular {@link Scheduler}.
+ *
+ *

+ * Example: + *


+     * Maybe.just(Notification.createOnNext(1))
+     * .dematerialize(notification -> notification)
+     * .test()
+     * .assertResult(1);
+     * 
+ * @param the result type + * @param selector the function called with the success item and should + * return a {@code Notification} instance. + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code selector} is {@code null} + * @since 3.0.0 + * @see #materialize() + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final <@NonNull R> Maybe dematerialize(@NonNull Function> selector) { + Objects.requireNonNull(selector, "selector is null"); + return RxJavaPlugins.onAssembly(new MaybeDematerialize<>(this, selector)); + } + + /** + * Returns a {@code Maybe} that signals the events emitted by the current {@code Maybe} shifted forward in time by a * specified delay. + * An error signal will not be delayed. *

- * + * *

*
Scheduler:
*
This version of {@code delay} operates by default on the {@code computation} {@link Scheduler}.
*
* - * @param delay + * @param time * the delay to shift the source by * @param unit - * the {@link TimeUnit} in which {@code period} is defined - * @return the new Maybe instance + * the {@link TimeUnit} in which {@code time} is defined + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @see ReactiveX operators documentation: Delay + * @see #delay(long, TimeUnit, Scheduler, boolean) + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.COMPUTATION) + @NonNull + public final Maybe delay(long time, @NonNull TimeUnit unit) { + return delay(time, unit, Schedulers.computation(), false); + } + + /** + * Returns a {@code Maybe} that signals the events emitted by the current {@code Maybe} shifted forward in time by a + * specified delay. + *

+ * + *

+ *
Scheduler:
+ *
This version of {@code delay} operates by default on the {@code computation} {@link Scheduler}.
+ *
+ * + * @param time the delay to shift the source by + * @param unit the {@link TimeUnit} in which {@code time} is defined + * @param delayError if {@code true}, both success and error signals are delayed. if {@code false}, only success signals are delayed. + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Delay - * @see #delay(long, TimeUnit, Scheduler) + * @see #delay(long, TimeUnit, Scheduler, boolean) + * @since 3.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Maybe delay(long delay, @NonNull TimeUnit unit) { - return delay(delay, unit, Schedulers.computation()); + public final Maybe delay(long time, @NonNull TimeUnit unit, boolean delayError) { + return delay(time, unit, Schedulers.computation(), delayError); } /** - * Returns a Maybe that signals the events emitted by the source Maybe shifted forward in time by a - * specified delay running on the specified Scheduler. + * Returns a {@code Maybe} that signals the events emitted by the current {@code Maybe} shifted forward in time by a + * specified delay. + * An error signal will not be delayed. *

- * + * + *

+ *
Scheduler:
+ *
you specify the {@link Scheduler} where the non-blocking wait and emission happens
+ *
+ * + * @param time the delay to shift the source by + * @param unit the {@link TimeUnit} in which {@code time} is defined + * @param scheduler the {@code Scheduler} to use for delaying + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @see ReactiveX operators documentation: Delay + * @see #delay(long, TimeUnit, Scheduler, boolean) + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.CUSTOM) + @NonNull + public final Maybe delay(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + return delay(time, unit, scheduler, false); + } + + /** + * Returns a {@code Maybe} that signals the events emitted by the current {@code Maybe} shifted forward in time by a + * specified delay running on the specified {@link Scheduler}. + *

+ * *

*
Scheduler:
- *
you specify which {@link Scheduler} this operator will use.
+ *
you specify which {@code Scheduler} this operator will use.
*
* - * @param delay + * @param time * the delay to shift the source by * @param unit - * the time unit of {@code delay} + * the {@link TimeUnit} in which {@code time} is defined * @param scheduler - * the {@link Scheduler} to use for delaying - * @return the new Maybe instance + * the {@code Scheduler} to use for delaying + * @param delayError if {@code true}, both success and error signals are delayed. if {@code false}, only success signals are delayed. + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Delay + * @since 3.0.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Maybe delay(long delay, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + public final Maybe delay(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new MaybeDelay<>(this, Math.max(0L, delay), unit, scheduler)); + return RxJavaPlugins.onAssembly(new MaybeDelay<>(this, Math.max(0L, time), unit, scheduler, delayError)); } /** - * Delays the emission of this Maybe until the given Publisher signals an item or completes. + * Delays the emission of this {@code Maybe} until the given {@link Publisher} signals an item or completes. *

- * + * *

*
Backpressure:
*
The {@code delayIndicator} is consumed in an unbounded manner but is cancelled after @@ -2670,23 +3436,24 @@ public final Maybe delay(long delay, @NonNull TimeUnit unit, @NonNull Schedul * @param * the subscription delay value type (ignored) * @param delayIndicator - * the Publisher that gets subscribed to when this Maybe signals an event and that - * signal is emitted when the Publisher signals an item or completes - * @return the new Maybe instance + * the {@code Publisher} that gets subscribed to when this {@code Maybe} signals an event and that + * signal is emitted when the {@code Publisher} signals an item or completes + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code delayIndicator} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) - public final Maybe delay(@NonNull Publisher delayIndicator) { + public final <@NonNull U> Maybe delay(@NonNull Publisher delayIndicator) { Objects.requireNonNull(delayIndicator, "delayIndicator is null"); return RxJavaPlugins.onAssembly(new MaybeDelayOtherPublisher<>(this, delayIndicator)); } /** - * Returns a Maybe that delays the subscription to this Maybe - * until the other Publisher emits an element or completes normally. + * Returns a {@code Maybe} that delays the subscription to this {@code Maybe} + * until the other {@link Publisher} emits an element or completes normally. *

* *

@@ -2696,23 +3463,23 @@ public final Maybe delay(@NonNull Publisher delayIndicator) { *
This method does not operate by default on a particular {@link Scheduler}.
*
* - * @param the value type of the other Publisher, irrelevant - * @param subscriptionIndicator the other Publisher that should trigger the subscription - * to this Publisher. - * @return a Maybe that delays the subscription to this Maybe - * until the other Publisher emits an element or completes normally. + * @param the value type of the other {@code Publisher}, irrelevant + * @param subscriptionIndicator the other {@code Publisher} that should trigger the subscription + * to this {@code Publisher}. + * @throws NullPointerException if {@code subscriptionIndicator} is {@code null} + * @return the new {@code Maybe} instance */ @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe delaySubscription(@NonNull Publisher subscriptionIndicator) { + public final <@NonNull U> Maybe delaySubscription(@NonNull Publisher subscriptionIndicator) { Objects.requireNonNull(subscriptionIndicator, "subscriptionIndicator is null"); return RxJavaPlugins.onAssembly(new MaybeDelaySubscriptionOtherPublisher<>(this, subscriptionIndicator)); } /** - * Returns a Maybe that delays the subscription to the source Maybe by a given amount of time. + * Returns a {@code Maybe} that delays the subscription to the current {@code Maybe} by a given amount of time. *

* *

@@ -2720,59 +3487,63 @@ public final Maybe delaySubscription(@NonNull Publisher subscriptionIn *
This version of {@code delaySubscription} operates by default on the {@code computation} {@link Scheduler}.
*
* - * @param delay + * @param time * the time to delay the subscription * @param unit * the time unit of {@code delay} - * @return a Maybe that delays the subscription to the source Maybe by the given amount + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Delay * @see #delaySubscription(long, TimeUnit, Scheduler) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Maybe delaySubscription(long delay, @NonNull TimeUnit unit) { - return delaySubscription(delay, unit, Schedulers.computation()); + public final Maybe delaySubscription(long time, @NonNull TimeUnit unit) { + return delaySubscription(time, unit, Schedulers.computation()); } /** - * Returns a Maybe that delays the subscription to the source Maybe by a given amount of time, - * both waiting and subscribing on a given Scheduler. + * Returns a {@code Maybe} that delays the subscription to the current {@code Maybe} by a given amount of time, + * both waiting and subscribing on a given {@link Scheduler}. *

* *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* - * @param delay + * @param time * the time to delay the subscription * @param unit * the time unit of {@code delay} * @param scheduler - * the Scheduler on which the waiting and subscription will happen - * @return a Maybe that delays the subscription to the source Maybe by a given - * amount, waiting and subscribing on the given Scheduler + * the {@code Scheduler} on which the waiting and subscription will happen + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Maybe delaySubscription(long delay, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return delaySubscription(Flowable.timer(delay, unit, scheduler)); + public final Maybe delaySubscription(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + return delaySubscription(Flowable.timer(time, unit, scheduler)); } /** - * Calls the specified consumer with the success item after this item has been emitted to the downstream. - *

Note that the {@code onAfterNext} action is shared between subscriptions and as such + * Calls the specified {@link Consumer} with the success item after this item has been emitted to the downstream. + *

Note that the {@code onAfterSuccess} action is shared between subscriptions and as such * should be thread-safe. + *

+ * *

*
Scheduler:
*
{@code doAfterSuccess} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.0.1 - experimental - * @param onAfterSuccess the Consumer that will be called after emitting an item from upstream to the downstream - * @return the new Maybe instance + * @param onAfterSuccess the {@code Consumer} that will be called after emitting an item from upstream to the downstream + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code onAfterSuccess} is {@code null} * @since 2.1 */ @CheckReturnValue @@ -2784,20 +3555,20 @@ public final Maybe doAfterSuccess(@NonNull Consumer onAfterSuccess } /** - * Registers an {@link Action} to be called when this Maybe invokes either + * Registers an {@link Action} to be called when this {@code Maybe} invokes either * {@link MaybeObserver#onComplete onSuccess}, * {@link MaybeObserver#onComplete onComplete} or {@link MaybeObserver#onError onError}. *

- * + * *

*
Scheduler:
*
{@code doAfterTerminate} does not operate by default on a particular {@link Scheduler}.
*
* * @param onAfterTerminate - * an {@link Action} to be invoked when the source Maybe finishes - * @return a Maybe that emits the same items as the source Maybe, then invokes the - * {@link Action} + * an {@code Action} to be invoked when the current {@code Maybe} finishes + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code onAfterTerminate} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -2815,9 +3586,12 @@ public final Maybe doAfterTerminate(@NonNull Action onAfterTerminate) { } /** - * Calls the specified action after this Maybe signals onSuccess, onError or onComplete or gets disposed by + * Calls the specified action after this {@code Maybe} signals {@code onSuccess}, {@code onError} or {@code onComplete} or gets disposed by * the downstream. - *

In case of a race between a terminal event and a dispose call, the provided {@code onFinally} action + *

+ * + *

+ * In case of a race between a terminal event and a dispose call, the provided {@code onFinally} action * is executed once per subscription. *

Note that the {@code onFinally} action is shared between subscriptions and as such * should be thread-safe. @@ -2826,8 +3600,9 @@ public final Maybe doAfterTerminate(@NonNull Action onAfterTerminate) { *

{@code doFinally} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.0.1 - experimental - * @param onFinally the action called when this Maybe terminates or gets disposed - * @return the new Maybe instance + * @param onFinally the action called when this {@code Maybe} terminates or gets disposed + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code onFinally} is {@code null} * @since 2.1 */ @CheckReturnValue @@ -2839,15 +3614,17 @@ public final Maybe doFinally(@NonNull Action onFinally) { } /** - * Calls the shared {@code Action} if a MaybeObserver subscribed to the current Maybe - * disposes the common Disposable it received via onSubscribe. + * Calls the shared {@link Action} if a {@link MaybeObserver} subscribed to the current {@code Maybe} + * disposes the common {@link Disposable} it received via {@code onSubscribe}. + *

+ * *

*
Scheduler:
*
{@code doOnDispose} does not operate by default on a particular {@link Scheduler}.
*
* @param onDispose the action called when the subscription is disposed - * @throws NullPointerException if onDispose is null - * @return the new Maybe instance + * @throws NullPointerException if {@code onDispose} is {@code null} + * @return the new {@code Maybe} instance */ @CheckReturnValue @NonNull @@ -2864,17 +3641,18 @@ public final Maybe doOnDispose(@NonNull Action onDispose) { } /** - * Modifies the source Maybe so that it invokes an action when it calls {@code onComplete}. + * Invokes an {@link Action} just before the current {@code Maybe} calls {@code onComplete}. *

- * + * *

*
Scheduler:
*
{@code doOnComplete} does not operate by default on a particular {@link Scheduler}.
*
* * @param onComplete - * the action to invoke when the source Maybe calls {@code onComplete} - * @return the new Maybe with the side-effecting behavior applied + * the action to invoke when the current {@code Maybe} calls {@code onComplete} + * @return the new {@code Maybe} with the side-effecting behavior applied + * @throws NullPointerException if {@code onComplete} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -2892,16 +3670,17 @@ public final Maybe doOnComplete(@NonNull Action onComplete) { } /** - * Calls the shared consumer with the error sent via onError for each - * MaybeObserver that subscribes to the current Maybe. + * Calls the shared {@link Consumer} with the error sent via {@code onError} for each + * {@link MaybeObserver} that subscribes to the current {@code Maybe}. *

- * + * *

*
Scheduler:
*
{@code doOnError} does not operate by default on a particular {@link Scheduler}.
*
- * @param onError the consumer called with the success value of onError - * @return the new Maybe instance + * @param onError the consumer called with the success value of {@code onError} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code onError} is {@code null} */ @CheckReturnValue @NonNull @@ -2918,38 +3697,70 @@ public final Maybe doOnError(@NonNull Consumer onError) { } /** - * Calls the given onEvent callback with the (success value, null) for an onSuccess, (null, throwable) for - * an onError or (null, null) for an onComplete signal from this Maybe before delivering said + * Calls the given {@code onEvent} callback with the (success value, {@code null}) for an {@code onSuccess}, ({@code null}, throwable) for + * an {@code onError} or ({@code null}, {@code null}) for an {@code onComplete} signal from this {@code Maybe} before delivering said * signal to the downstream. *

* *

- * Exceptions thrown from the callback will override the event so the downstream receives the + * The exceptions thrown from the callback will override the event so the downstream receives the * error instead of the original signal. *

*
Scheduler:
*
{@code doOnEvent} does not operate by default on a particular {@link Scheduler}.
*
- * @param onEvent the callback to call with the terminal event tuple - * @return the new Maybe instance + * @param onEvent the callback to call with the success value or the exception, whichever is not {@code null} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code onEvent} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Maybe doOnEvent(@NonNull BiConsumer onEvent) { + public final Maybe doOnEvent(@NonNull BiConsumer<@Nullable ? super T, @Nullable ? super Throwable> onEvent) { Objects.requireNonNull(onEvent, "onEvent is null"); return RxJavaPlugins.onAssembly(new MaybeDoOnEvent<>(this, onEvent)); } /** - * Calls the shared consumer with the Disposable sent through the onSubscribe for each - * MaybeObserver that subscribes to the current Maybe. + * Calls the appropriate {@code onXXX} method (shared between all {@link MaybeObserver}s) for the lifecycle events of + * the sequence (subscription, disposal). + *

+ * + *

+ *
Scheduler:
+ *
{@code doOnLifecycle} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param onSubscribe + * a {@link Consumer} called with the {@link Disposable} sent via {@link MaybeObserver#onSubscribe(Disposable)} + * @param onDispose + * called when the downstream disposes the {@code Disposable} via {@code dispose()} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code onSubscribe} or {@code onDispose} is {@code null} + * @see ReactiveX operators documentation: Do + * @since 3.0.0 + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Maybe doOnLifecycle(@NonNull Consumer onSubscribe, @NonNull Action onDispose) { + Objects.requireNonNull(onSubscribe, "onSubscribe is null"); + Objects.requireNonNull(onDispose, "onDispose is null"); + return RxJavaPlugins.onAssembly(new MaybeDoOnLifecycle<>(this, onSubscribe, onDispose)); + } + + /** + * Calls the shared {@link Consumer} with the {@link Disposable} sent through the {@code onSubscribe} for each + * {@link MaybeObserver} that subscribes to the current {@code Maybe}. + *

+ * *

*
Scheduler:
*
{@code doOnSubscribe} does not operate by default on a particular {@link Scheduler}.
*
- * @param onSubscribe the consumer called with the Disposable sent via onSubscribe - * @return the new Maybe instance + * @param onSubscribe the {@code Consumer} called with the {@code Disposable} sent via {@code onSubscribe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code onSubscribe} is {@code null} */ @CheckReturnValue @NonNull @@ -2966,10 +3777,10 @@ public final Maybe doOnSubscribe(@NonNull Consumer onSubs } /** - * Returns a Maybe instance that calls the given onTerminate callback - * just before this Maybe completes normally or with an exception. + * Returns a {@code Maybe} instance that calls the given onTerminate callback + * just before this {@code Maybe} completes normally or with an exception. *

- * + * *

* This differs from {@code doAfterTerminate} in that this happens before the {@code onComplete} or * {@code onError} notification. @@ -2979,7 +3790,8 @@ public final Maybe doOnSubscribe(@NonNull Consumer onSubs *

*

History: 2.2.7 - experimental * @param onTerminate the action to invoke when the consumer calls {@code onComplete} or {@code onError} - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code onTerminate} is {@code null} * @see ReactiveX operators documentation: Do * @see #doOnTerminate(Action) * @since 3.0.0 @@ -2993,16 +3805,17 @@ public final Maybe doOnTerminate(@NonNull Action onTerminate) { } /** - * Calls the shared consumer with the success value sent via onSuccess for each - * MaybeObserver that subscribes to the current Maybe. + * Calls the shared {@link Consumer} with the success value sent via {@code onSuccess} for each + * {@link MaybeObserver} that subscribes to the current {@code Maybe}. *

- * + * *

*
Scheduler:
*
{@code doOnSuccess} does not operate by default on a particular {@link Scheduler}.
*
- * @param onSuccess the consumer called with the success value of onSuccess - * @return the new Maybe instance + * @param onSuccess the {@code Consumer} called with the success value of the upstream + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code onSuccess} is {@code null} */ @CheckReturnValue @NonNull @@ -3019,20 +3832,20 @@ public final Maybe doOnSuccess(@NonNull Consumer onSuccess) { } /** - * Filters the success item of the Maybe via a predicate function and emitting it if the predicate - * returns true, completing otherwise. + * Filters the success item of the {@code Maybe} via a predicate function and emitting it if the predicate + * returns {@code true}, completing otherwise. *

- * + * *

*
Scheduler:
*
{@code filter} does not operate by default on a particular {@link Scheduler}.
*
* * @param predicate - * a function that evaluates the item emitted by the source Maybe, returning {@code true} + * a function that evaluates the item emitted by the current {@code Maybe}, returning {@code true} * if it passes the filter - * @return a Maybe that emit the item emitted by the source Maybe that the filter - * evaluates as {@code true} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @see ReactiveX operators documentation: Filter */ @CheckReturnValue @@ -3044,33 +3857,34 @@ public final Maybe filter(@NonNull Predicate predicate) { } /** - * Returns a Maybe that is based on applying a specified function to the item emitted by the source Maybe, - * where that function returns a MaybeSource. + * Returns a {@code Maybe} that is based on applying a specified function to the item emitted by the current {@code Maybe}, + * where that function returns a {@link MaybeSource}. *

- * + * *

*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
*
- *

Note that flatMap and concatMap for Maybe is the same operation. + *

Note that flatMap and concatMap for {@code Maybe} is the same operation. * * @param the result value type * @param mapper - * a function that, when applied to the item emitted by the source Maybe, returns a MaybeSource - * @return the Maybe returned from {@code func} when applied to the item emitted by the source Maybe + * a function that, when applied to the item emitted by the current {@code Maybe}, returns a {@code MaybeSource} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe flatMap(@NonNull Function> mapper) { + public final <@NonNull R> Maybe flatMap(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new MaybeFlatten<>(this, mapper)); } /** - * Maps the onSuccess, onError or onComplete signals of this Maybe into MaybeSource and emits that - * MaybeSource's signals. + * Maps the {@code onSuccess}, {@code onError} or {@code onComplete} signals of the current {@code Maybe} into a {@link MaybeSource} and emits that + * {@code MaybeSource}'s signals. *

* *

@@ -3081,18 +3895,19 @@ public final Maybe flatMap(@NonNull Function * the result type * @param onSuccessMapper - * a function that returns a MaybeSource to merge for the onSuccess item emitted by this Maybe + * a function that returns a {@code MaybeSource} to merge for the {@code onSuccess} item emitted by this {@code Maybe} * @param onErrorMapper - * a function that returns a MaybeSource to merge for an onError notification from this Maybe + * a function that returns a {@code MaybeSource} to merge for an {@code onError} notification from this {@code Maybe} * @param onCompleteSupplier - * a function that returns a MaybeSource to merge for an onComplete notification this Maybe - * @return the new Maybe instance + * a function that returns a {@code MaybeSource} to merge for an {@code onComplete} notification this {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code onSuccessMapper}, {@code onErrorMapper} or {@code onCompleteSupplier} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe flatMap( + public final <@NonNull R> Maybe flatMap( @NonNull Function> onSuccessMapper, @NonNull Function> onErrorMapper, @NonNull Supplier> onCompleteSupplier) { @@ -3103,39 +3918,40 @@ public final Maybe flatMap( } /** - * Returns a Maybe that emits the results of a specified function to the pair of values emitted by the - * source Maybe and a specified mapped MaybeSource. + * Returns a {@code Maybe} that emits the results of a specified function to the pair of values emitted by the + * current {@code Maybe} and a specified mapped {@link MaybeSource}. *

- * + * *

*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items emitted by the MaybeSource returned by the {@code mapper} function + * the type of items emitted by the {@code MaybeSource} returned by the {@code mapper} function * @param - * the type of items emitted by the resulting Maybe + * the type of items emitted by the resulting {@code Maybe} * @param mapper - * a function that returns a MaybeSource for the item emitted by the source Maybe - * @param resultSelector - * a function that combines one item emitted by each of the source and collection MaybeSource and - * returns an item to be emitted by the resulting MaybeSource - * @return the new Maybe instance + * a function that returns a {@code MaybeSource} for the item emitted by the current {@code Maybe} + * @param combiner + * a function that combines one item emitted by each of the source and collection {@code MaybeSource} and + * returns an item to be emitted by the resulting {@code MaybeSource} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe flatMap(@NonNull Function> mapper, - @NonNull BiFunction resultSelector) { + public final <@NonNull U, @NonNull R> Maybe flatMap(@NonNull Function> mapper, + @NonNull BiFunction combiner) { Objects.requireNonNull(mapper, "mapper is null"); - Objects.requireNonNull(resultSelector, "resultSelector is null"); - return RxJavaPlugins.onAssembly(new MaybeFlatMapBiSelector<>(this, mapper, resultSelector)); + Objects.requireNonNull(combiner, "combiner is null"); + return RxJavaPlugins.onAssembly(new MaybeFlatMapBiSelector<>(this, mapper, combiner)); } /** - * Maps the success value of the upstream {@link Maybe} into an {@link Iterable} and emits its items as a + * Maps the success value of the current {@code Maybe} into an {@link Iterable} and emits its items as a * {@link Flowable} sequence. *

* @@ -3147,11 +3963,12 @@ public final Maybe flatMap(@NonNull Function * * @param - * the type of item emitted by the resulting Iterable + * the type of item emitted by the inner {@code Iterable} * @param mapper - * a function that returns an Iterable sequence of values for when given an item emitted by the - * source Maybe - * @return the new Flowable instance + * a function that returns an {@code Iterable} sequence of values for when given an item emitted by the + * current {@code Maybe} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap * @see #flattenStreamAsFlowable(Function) */ @@ -3159,13 +3976,13 @@ public final Maybe flatMap(@NonNull Function Flowable flattenAsFlowable(@NonNull Function> mapper) { + public final <@NonNull U> Flowable flattenAsFlowable(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new MaybeFlatMapIterableFlowable<>(this, mapper)); } /** - * Maps the success value of the upstream {@link Maybe} into an {@link Iterable} and emits its items as an + * Maps the success value of the current {@code Maybe} into an {@link Iterable} and emits its items as an * {@link Observable} sequence. *

* @@ -3175,26 +3992,27 @@ public final Flowable flattenAsFlowable(@NonNull Function * * @param - * the type of item emitted by the resulting Iterable + * the type of item emitted by the resulting {@code Iterable} * @param mapper - * a function that returns an Iterable sequence of values for when given an item emitted by the - * source Maybe - * @return the new Observable instance + * a function that returns an {@code Iterable} sequence of values for when given an item emitted by the + * current {@code Maybe} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Observable flattenAsObservable(@NonNull Function> mapper) { + public final <@NonNull U> Observable flattenAsObservable(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new MaybeFlatMapIterableObservable<>(this, mapper)); } /** - * Returns an Observable that is based on applying a specified function to the item emitted by the source Maybe, - * where that function returns an ObservableSource. + * Returns an {@link Observable} that is based on applying a specified function to the item emitted by the current {@code Maybe}, + * where that function returns an {@link ObservableSource}. *

- * + * *

*
Scheduler:
*
{@code flatMapObservable} does not operate by default on a particular {@link Scheduler}.
@@ -3202,114 +4020,92 @@ public final Observable flattenAsObservable(@NonNull Function the result value type * @param mapper - * a function that, when applied to the item emitted by the source Maybe, returns an ObservableSource - * @return the Observable returned from {@code func} when applied to the item emitted by the source Maybe + * a function that, when applied to the item emitted by the current {@code Maybe}, returns an {@code ObservableSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Observable flatMapObservable(@NonNull Function> mapper) { + public final <@NonNull R> Observable flatMapObservable(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new MaybeFlatMapObservable<>(this, mapper)); } /** - * Returns a Flowable that emits items based on applying a specified function to the item emitted by the - * source Maybe, where that function returns a Publisher. + * Returns a {@link Flowable} that emits items based on applying a specified function to the item emitted by the + * current {@code Maybe}, where that function returns a {@link Publisher}. *

- * + * *

*
Backpressure:
- *
The returned Flowable honors the downstream backpressure.
+ *
The returned {@code Flowable} honors the downstream backpressure.
*
Scheduler:
*
{@code flatMapPublisher} does not operate by default on a particular {@link Scheduler}.
*
* * @param the result value type * @param mapper - * a function that, when applied to the item emitted by the source Maybe, returns a - * Flowable - * @return the Flowable returned from {@code func} when applied to the item emitted by the source Maybe + * a function that, when applied to the item emitted by the current {@code Maybe}, returns a + * {@code Flowable} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable flatMapPublisher(@NonNull Function> mapper) { + public final <@NonNull R> Flowable flatMapPublisher(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new MaybeFlatMapPublisher<>(this, mapper)); } /** - * Returns a {@link Single} based on applying a specified function to the item emitted by the - * source {@link Maybe}, where that function returns a {@link Single}. - * When this Maybe completes a {@link NoSuchElementException} will be thrown. + * Returns a {@code Maybe} based on applying a specified function to the item emitted by the + * current {@code Maybe}, where that function returns a {@link Single}. + * When this {@code Maybe} just completes the resulting {@code Maybe} completes as well. *

- * + * *

*
Scheduler:
*
{@code flatMapSingle} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the result value type - * @param mapper - * a function that, when applied to the item emitted by the source Maybe, returns a - * Single - * @return the Single returned from {@code mapper} when applied to the item emitted by the source Maybe - * @see ReactiveX operators documentation: FlatMap - */ - @CheckReturnValue - @NonNull - @SchedulerSupport(SchedulerSupport.NONE) - public final Single flatMapSingle(@NonNull Function> mapper) { - Objects.requireNonNull(mapper, "mapper is null"); - return RxJavaPlugins.onAssembly(new MaybeFlatMapSingle<>(this, mapper)); - } - - /** - * Returns a {@link Maybe} based on applying a specified function to the item emitted by the - * source {@link Maybe}, where that function returns a {@link Single}. - * When this Maybe just completes the resulting {@code Maybe} completes as well. - *

- * - *

- *
Scheduler:
- *
{@code flatMapSingleElement} does not operate by default on a particular {@link Scheduler}.
- *
- * *

History: 2.0.2 - experimental * @param the result value type * @param mapper - * a function that, when applied to the item emitted by the source Maybe, returns a - * Single - * @return the new Maybe instance + * a function that, when applied to the item emitted by the current {@code Maybe}, returns a + * {@code Single} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap * @since 2.1 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe flatMapSingleElement(@NonNull Function> mapper) { + public final <@NonNull R> Maybe flatMapSingle(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); - return RxJavaPlugins.onAssembly(new MaybeFlatMapSingleElement<>(this, mapper)); + return RxJavaPlugins.onAssembly(new MaybeFlatMapSingle<>(this, mapper)); } /** * Returns a {@link Completable} that completes based on applying a specified function to the item emitted by the - * source {@link Maybe}, where that function returns a {@link Completable}. + * current {@code Maybe}, where that function returns a {@code Completable}. *

- * + * *

*
Scheduler:
*
{@code flatMapCompletable} does not operate by default on a particular {@link Scheduler}.
*
* * @param mapper - * a function that, when applied to the item emitted by the source Maybe, returns a - * Completable - * @return the Completable returned from {@code mapper} when applied to the item emitted by the source Maybe + * a function that, when applied to the item emitted by the current {@code Maybe}, returns a + * {@code Completable} + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @@ -3321,7 +4117,7 @@ public final Completable flatMapCompletable(@NonNull Function * *

Allows preventing certain identity-based @@ -3330,7 +4126,7 @@ public final Completable flatMapCompletable(@NonNull FunctionScheduler: *

{@code hide} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new Maybe instance + * @return the new {@code Maybe} instance */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -3340,16 +4136,15 @@ public final Maybe hide() { } /** - * Ignores the item emitted by the source Maybe and only calls {@code onComplete} or {@code onError}. + * Returns a {@link Completable} that ignores the item emitted by the current {@code Maybe} and only calls {@code onComplete} or {@code onError}. *

- * + * *

*
Scheduler:
*
{@code ignoreElement} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an empty Completable that only calls {@code onComplete} or {@code onError}, based on which one is - * called by the source Maybe + * @return the new {@code Completable} instance * @see ReactiveX operators documentation: IgnoreElements */ @CheckReturnValue @@ -3360,15 +4155,15 @@ public final Completable ignoreElement() { } /** - * Returns a Single that emits {@code true} if the source Maybe is empty, otherwise {@code false}. + * Returns a {@link Single} that emits {@code true} if the current {@code Maybe} is empty, otherwise {@code false}. *

- * + * *

*
Scheduler:
*
{@code isEmpty} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a Single that emits a Boolean + * @return the new {@code Single} instance * @see ReactiveX operators documentation: Contains */ @CheckReturnValue @@ -3382,7 +4177,7 @@ public final Single isEmpty() { * This method requires advanced knowledge about building operators, please consider * other standard composition methods first; * Returns a {@code Maybe} which, when subscribed to, invokes the {@link MaybeOperator#apply(MaybeObserver) apply(MaybeObserver)} method - * of the provided {@link MaybeOperator} for each individual downstream {@link Maybe} and allows the + * of the provided {@link MaybeOperator} for each individual downstream {@code Maybe} and allows the * insertion of a custom operator by accessing the downstream's {@link MaybeObserver} during this subscription phase * and providing a new {@code MaybeObserver}, containing the custom operator's intended business logic, that will be * used in the subscription process going further upstream. @@ -3435,7 +4230,7 @@ public final Single isEmpty() { * if (str.length() < 2) { * downstream.onSuccess(str); * } else { - * // Maybe is usually expected to produce one of the onXXX events + * // Maybe is expected to produce one of the onXXX events only * downstream.onComplete(); * } * } @@ -3507,36 +4302,37 @@ public final Single isEmpty() { * class and creating a {@link MaybeTransformer} with it is recommended. *

* Note also that it is not possible to stop the subscription phase in {@code lift()} as the {@code apply()} method - * requires a non-null {@code MaybeObserver} instance to be returned, which is then unconditionally subscribed to - * the upstream {@code Maybe}. For example, if the operator decided there is no reason to subscribe to the + * requires a non-{@code null} {@code MaybeObserver} instance to be returned, which is then unconditionally subscribed to + * the current {@code Maybe}. For example, if the operator decided there is no reason to subscribe to the * upstream source because of some optimization possibility or a failure to prepare the operator, it still has to - * return a {@code MaybeObserver} that should immediately dispose the upstream's {@code Disposable} in its + * return a {@code MaybeObserver} that should immediately dispose the upstream's {@link Disposable} in its * {@code onSubscribe} method. Again, using a {@code MaybeTransformer} and extending the {@code Maybe} is * a better option as {@link #subscribeActual} can decide to not subscribe to its upstream after all. *

*
Scheduler:
*
{@code lift} does not operate by default on a particular {@link Scheduler}, however, the - * {@link MaybeOperator} may use a {@code Scheduler} to support its own asynchronous behavior.
+ * {@code MaybeOperator} may use a {@code Scheduler} to support its own asynchronous behavior.
*
* * @param the output value type - * @param lift the {@link MaybeOperator} that receives the downstream's {@code MaybeObserver} and should return + * @param lift the {@code MaybeOperator} that receives the downstream's {@code MaybeObserver} and should return * a {@code MaybeObserver} with custom behavior to be used as the consumer for the current * {@code Maybe}. - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code lift} is {@code null} * @see RxJava wiki: Writing operators * @see #compose(MaybeTransformer) */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe lift(@NonNull MaybeOperator lift) { + public final <@NonNull R> Maybe lift(@NonNull MaybeOperator lift) { Objects.requireNonNull(lift, "lift is null"); return RxJavaPlugins.onAssembly(new MaybeLift<>(this, lift)); } /** - * Returns a Maybe that applies a specified function to the item emitted by the source Maybe and + * Returns a {@code Maybe} that applies a specified function to the item emitted by the current {@code Maybe} and * emits the result of this function application. *

* @@ -3547,29 +4343,30 @@ public final Maybe lift(@NonNull MaybeOperator li * * @param the result value type * @param mapper - * a function to apply to the item emitted by the Maybe - * @return a Maybe that emits the item from the source Maybe, transformed by the specified function + * a function to apply to the item emitted by the {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: Map */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe map(@NonNull Function mapper) { + public final <@NonNull R> Maybe map(@NonNull Function mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new MaybeMap<>(this, mapper)); } /** - * Maps the signal types of this Maybe into a {@link Notification} of the same kind - * and emits it as a single success value to downstream. + * Maps the signal types of this {@code Maybe} into a {@link Notification} of the same kind + * and emits it as a {@link Single}'s {@code onSuccess} value to downstream. *

- * + * *

*
Scheduler:
*
{@code materialize} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.2.4 - experimental - * @return the new Single instance + * @return the new {@code Single} instance * @since 3.0.0 * @see Single#dematerialize(Function) */ @@ -3581,11 +4378,11 @@ public final Single> materialize() { } /** - * Flattens this and another Maybe into a single Flowable, without any transformation. + * Flattens this {@code Maybe} and another {@link MaybeSource} into a single {@link Flowable}, without any transformation. *

- * + * *

- * You can combine items emitted by multiple Maybes so that they appear as a single Flowable, by + * You can combine items emitted by multiple {@code Maybe}s so that they appear as a single {@code Flowable}, by * using the {@code mergeWith} method. *

*
Backpressure:
@@ -3595,8 +4392,9 @@ public final Single> materialize() { *
* * @param other - * a MaybeSource to be merged - * @return a new Flowable instance + * a {@code MaybeSource} to be merged + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: Merge */ @BackpressureSupport(BackpressureKind.FULL) @@ -3609,19 +4407,20 @@ public final Flowable mergeWith(@NonNull MaybeSource other) { } /** - * Wraps a Maybe to emit its item (or notify of its error) on a specified {@link Scheduler}, + * Wraps a {@code Maybe} to emit its item (or notify of its error) on a specified {@link Scheduler}, * asynchronously. *

- * + * *

*
Scheduler:
- *
you specify which {@link Scheduler} this operator will use.
+ *
you specify which {@code Scheduler} this operator will use.
*
* * @param scheduler - * the {@link Scheduler} to notify subscribers on - * @return the new Maybe instance that its subscribers are notified on the specified - * {@link Scheduler} + * the {@code Scheduler} to notify subscribers on + * @return the new {@code Maybe} instance that its subscribers are notified on the specified + * {@code Scheduler} + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: ObserveOn * @see RxJava Threading Examples * @see #subscribeOn @@ -3635,10 +4434,10 @@ public final Maybe observeOn(@NonNull Scheduler scheduler) { } /** - * Filters the items emitted by a Maybe, only emitting its success value if that - * is an instance of the supplied Class. + * Filters the items emitted by the current {@code Maybe}, only emitting its success value if that + * is an instance of the supplied {@link Class}. *

- * + * *

*
Scheduler:
*
{@code ofType} does not operate by default on a particular {@link Scheduler}.
@@ -3646,14 +4445,15 @@ public final Maybe observeOn(@NonNull Scheduler scheduler) { * * @param the output type * @param clazz - * the class type to filter the items emitted by the source Maybe - * @return the new Maybe instance + * the class type to filter the items emitted by the current {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code clazz} is {@code null} * @see ReactiveX operators documentation: Filter */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe ofType(@NonNull Class clazz) { + public final <@NonNull U> Maybe ofType(@NonNull Class clazz) { Objects.requireNonNull(clazz, "clazz is null"); return filter(Functions.isInstanceOf(clazz)).cast(clazz); } @@ -3661,6 +4461,8 @@ public final Maybe ofType(@NonNull Class clazz) { /** * Calls the specified converter function during assembly time and returns its resulting value. *

+ * + *

* This allows fluent conversion to any other type. *

*
Scheduler:
@@ -3668,9 +4470,9 @@ public final Maybe ofType(@NonNull Class clazz) { *
*

History: 2.1.7 - experimental * @param the resulting object type - * @param converter the function that receives the current Maybe instance and returns a value + * @param converter the function that receives the current {@code Maybe} instance and returns a value * @return the converted value - * @throws NullPointerException if converter is null + * @throws NullPointerException if {@code converter} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -3680,15 +4482,17 @@ public final R to(@NonNull MaybeConverter converter) { } /** - * Converts this Maybe into a backpressure-aware Flowable instance composing cancellation + * Converts this {@code Maybe} into a backpressure-aware {@link Flowable} instance composing cancellation * through. + *

+ * *

*
Backpressure:
- *
The returned Flowable honors the backpressure of the downstream.
+ *
The returned {@code Flowable} honors the backpressure of the downstream.
*
Scheduler:
*
{@code toFlowable} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new Flowable instance + * @return the new {@code Flowable} instance */ @SuppressWarnings("unchecked") @BackpressureSupport(BackpressureKind.FULL) @@ -3703,13 +4507,38 @@ public final Flowable toFlowable() { } /** - * Converts this Maybe into an Observable instance composing disposal + * Returns a {@link Future} representing the single value emitted by the current {@code Maybe} + * or {@code null} if the current {@code Maybe} is empty. + *

+ * + *

+ * Cancelling the {@code Future} will cancel the subscription to the current {@code Maybe}. + *

+ *
Scheduler:
+ *
{@code toFuture} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @return the new {@code Future} instance + * @see ReactiveX documentation: To + * @since 3.0.0 + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Future toFuture() { + return subscribeWith(new FutureMultiObserver<>()); + } + + /** + * Converts this {@code Maybe} into an {@link Observable} instance composing disposal * through. + *

+ * *

*
Scheduler:
*
{@code toObservable} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new Observable instance + * @return the new {@code Observable} instance */ @SuppressWarnings("unchecked") @CheckReturnValue @@ -3723,13 +4552,16 @@ public final Observable toObservable() { } /** - * Converts this Maybe into a Single instance composing disposal - * through and turning an empty Maybe into a signal of NoSuchElementException. + * Converts this {@code Maybe} into a {@link Single} instance composing disposal + * through and turning an empty {@code Maybe} into a signal of {@link NoSuchElementException}. + *

+ * *

*
Scheduler:
*
{@code toSingle} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new Single instance + * @return the new {@code Single} instance + * @see #defaultIfEmpty(Object) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -3739,13 +4571,15 @@ public final Single toSingle() { } /** - * Returns a Maybe instance that if this Maybe emits an error, it will emit an onComplete + * Returns a {@code Maybe} instance that if this {@code Maybe} emits an error, it will emit an {@code onComplete} * and swallow the throwable. + *

+ * *

*
Scheduler:
*
{@code onErrorComplete} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new Maybe instance + * @return the new {@code Maybe} instance */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -3755,15 +4589,18 @@ public final Maybe onErrorComplete() { } /** - * Returns a Maybe instance that if this Maybe emits an error and the predicate returns - * true, it will emit an onComplete and swallow the throwable. + * Returns a {@code Maybe} instance that if this {@code Maybe} emits an error and the predicate returns + * {@code true}, it will emit an {@code onComplete} and swallow the throwable. + *

+ * *

*
Scheduler:
*
{@code onErrorComplete} does not operate by default on a particular {@link Scheduler}.
*
- * @param predicate the predicate to call when an Throwable is emitted which should return true - * if the Throwable should be swallowed and replaced with an onComplete. - * @return the new Maybe instance + * @param predicate the predicate to call when an {@link Throwable} is emitted which should return {@code true} + * if the {@code Throwable} should be swallowed and replaced with an {@code onComplete}. + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code predicate} is {@code null} */ @CheckReturnValue @NonNull @@ -3775,10 +4612,10 @@ public final Maybe onErrorComplete(@NonNull Predicate pred } /** - * Instructs a Maybe to pass control to another {@link MaybeSource} rather than invoking - * {@link MaybeObserver#onError onError} if it encounters an error. + * Resumes the flow with the given {@link MaybeSource} when the current {@code Maybe} fails instead of + * signaling the error via {@code onError}. *

- * + * *

* You can use this to prevent errors from propagating or to supply fallback data should errors be * encountered. @@ -3787,25 +4624,26 @@ public final Maybe onErrorComplete(@NonNull Predicate pred *

{@code onErrorResumeWith} does not operate by default on a particular {@link Scheduler}.
*
* - * @param next - * the next {@code MaybeSource} that will take over if the source Maybe encounters + * @param fallback + * the next {@code MaybeSource} that will take over if the current {@code Maybe} encounters * an error - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code fallback} is {@code null} * @see ReactiveX operators documentation: Catch */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe onErrorResumeWith(@NonNull MaybeSource next) { - Objects.requireNonNull(next, "next is null"); - return onErrorResumeNext(Functions.justFunction(next)); + public final Maybe onErrorResumeWith(@NonNull MaybeSource fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return onErrorResumeNext(Functions.justFunction(fallback)); } /** - * Instructs a Maybe to pass control to another Maybe rather than invoking - * {@link MaybeObserver#onError onError} if it encounters an error. + * Resumes the flow with a {@link MaybeSource} returned for the failure {@link Throwable} of the current {@code Maybe} by a + * function instead of signaling the error via {@code onError}. *

- * + * *

* You can use this to prevent errors from propagating or to supply fallback data should errors be * encountered. @@ -3814,25 +4652,26 @@ public final Maybe onErrorResumeWith(@NonNull MaybeSource next) *

{@code onErrorResumeNext} does not operate by default on a particular {@link Scheduler}.
*
* - * @param resumeFunction - * a function that returns a MaybeSource that will take over if the source Maybe encounters + * @param fallbackSupplier + * a function that returns a {@code MaybeSource} that will take over if the current {@code Maybe} encounters * an error - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code fallbackSupplier} is {@code null} * @see ReactiveX operators documentation: Catch */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe onErrorResumeNext(@NonNull Function> resumeFunction) { - Objects.requireNonNull(resumeFunction, "resumeFunction is null"); - return RxJavaPlugins.onAssembly(new MaybeOnErrorNext<>(this, resumeFunction, true)); + public final Maybe onErrorResumeNext(@NonNull Function> fallbackSupplier) { + Objects.requireNonNull(fallbackSupplier, "fallbackSupplier is null"); + return RxJavaPlugins.onAssembly(new MaybeOnErrorNext<>(this, fallbackSupplier)); } /** - * Instructs a Maybe to emit an item (returned by a specified function) rather than invoking - * {@link MaybeObserver#onError onError} if it encounters an error. + * Ends the flow with a success item returned by a function for the {@link Throwable} error signaled by the current + * {@code Maybe} instead of signaling the error via {@code onError}. *

- * + * *

* You can use this to prevent errors from propagating or to supply fallback data should errors be * encountered. @@ -3841,25 +4680,25 @@ public final Maybe onErrorResumeNext(@NonNull Function{@code onErrorReturn} does not operate by default on a particular {@link Scheduler}.

*
* - * @param valueSupplier + * @param itemSupplier * a function that returns a single value that will be emitted as success value - * the current Maybe signals an onError event - * @return the new Maybe instance + * the current {@code Maybe} signals an {@code onError} event + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code itemSupplier} is {@code null} * @see ReactiveX operators documentation: Catch */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe onErrorReturn(@NonNull Function valueSupplier) { - Objects.requireNonNull(valueSupplier, "valueSupplier is null"); - return RxJavaPlugins.onAssembly(new MaybeOnErrorReturn<>(this, valueSupplier)); + public final Maybe onErrorReturn(@NonNull Function itemSupplier) { + Objects.requireNonNull(itemSupplier, "itemSupplier is null"); + return RxJavaPlugins.onAssembly(new MaybeOnErrorReturn<>(this, itemSupplier)); } /** - * Instructs a Maybe to emit an item (returned by a specified function) rather than invoking - * {@link MaybeObserver#onError onError} if it encounters an error. + * Ends the flow with the given success item when the current {@code Maybe} fails instead of signaling the error via {@code onError}. *

- * + * *

* You can use this to prevent errors from propagating or to supply fallback data should errors be * encountered. @@ -3869,8 +4708,9 @@ public final Maybe onErrorReturn(@NonNull Function * * @param item - * the value that is emitted as onSuccess in case this Maybe signals an onError - * @return the new Maybe instance + * the value that is emitted as {@code onSuccess} in case the current {@code Maybe} signals an {@code onError} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code item} is {@code null} * @see ReactiveX operators documentation: Catch */ @CheckReturnValue @@ -3882,46 +4722,16 @@ public final Maybe onErrorReturnItem(@NonNull T item) { } /** - * Instructs a Maybe to pass control to another MaybeSource rather than invoking - * {@link MaybeObserver#onError onError} if it encounters an {@link java.lang.Exception}. - *

- * This differs from {@link #onErrorResumeNext} in that this one does not handle {@link java.lang.Throwable} - * or {@link java.lang.Error} but lets those continue through. - *

- * - *

- * You can use this to prevent exceptions from propagating or to supply fallback data should exceptions be - * encountered. - *

- *
Scheduler:
- *
{@code onExceptionResumeNext} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param next - * the next MaybeSource that will take over if the source Maybe encounters - * an exception - * @return the new Maybe instance - * @see ReactiveX operators documentation: Catch - */ - @CheckReturnValue - @NonNull - @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe onExceptionResumeNext(@NonNull MaybeSource next) { - Objects.requireNonNull(next, "next is null"); - return RxJavaPlugins.onAssembly(new MaybeOnErrorNext<>(this, Functions.justFunction(next), false)); - } - - /** - * Nulls out references to the upstream producer and downstream MaybeObserver if - * the sequence is terminated or downstream calls dispose(). + * Nulls out references to the upstream producer and downstream {@link MaybeObserver} if + * the sequence is terminated or downstream calls {@code dispose()}. *

* *

*
Scheduler:
*
{@code onTerminateDetach} does not operate by default on a particular {@link Scheduler}.
*
- * @return a Maybe which nulls out references to the upstream producer and downstream MaybeObserver if - * the sequence is terminated or downstream calls dispose() + * @return the new {@code Maybe} instance + * the sequence is terminated or downstream calls {@code dispose()} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -3931,9 +4741,9 @@ public final Maybe onTerminateDetach() { } /** - * Returns a Flowable that repeats the sequence of items emitted by the source Maybe indefinitely. + * Returns a {@link Flowable} that repeats the sequence of items emitted by the current {@code Maybe} indefinitely. *

- * + * *

*
Backpressure:
*
The operator honors downstream backpressure.
@@ -3941,7 +4751,7 @@ public final Maybe onTerminateDetach() { *
{@code repeat} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a Flowable that emits the items emitted by the source Maybe repeatedly and in sequence + * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: Repeat */ @BackpressureSupport(BackpressureKind.FULL) @@ -3953,10 +4763,10 @@ public final Flowable repeat() { } /** - * Returns a Flowable that repeats the sequence of items emitted by the source Maybe at most + * Returns a {@link Flowable} that repeats the sequence of items emitted by the current {@code Maybe} at most * {@code count} times. *

- * + * *

*
Backpressure:
*
This operator honors downstream backpressure.
@@ -3965,12 +4775,11 @@ public final Flowable repeat() { *
* * @param times - * the number of times the source Maybe items are repeated, a count of 0 will yield an empty + * the number of times the current {@code Maybe} items are repeated, a count of 0 will yield an empty * sequence - * @return a Flowable that repeats the sequence of items emitted by the source Maybe at most - * {@code count} times + * @return the new {@code Flowable} instance * @throws IllegalArgumentException - * if {@code count} is less than zero + * if {@code times} is negative * @see ReactiveX operators documentation: Repeat */ @BackpressureSupport(BackpressureKind.FULL) @@ -3982,10 +4791,10 @@ public final Flowable repeat(long times) { } /** - * Returns a Flowable that repeats the sequence of items emitted by the source Maybe until - * the provided stop function returns true. + * Returns a {@link Flowable} that repeats the sequence of items emitted by the current {@code Maybe} until + * the provided stop function returns {@code true}. *

- * + * *

*
Backpressure:
*
This operator honors downstream backpressure.
@@ -3994,11 +4803,11 @@ public final Flowable repeat(long times) { *
* * @param stop - * a boolean supplier that is called when the current Flowable completes and unless it returns - * false, the current Flowable is resubscribed - * @return the new Flowable instance + * a boolean supplier that is called when the current {@code Flowable} completes and unless it returns + * {@code false}, the current {@code Flowable} is resubscribed + * @return the new {@code Flowable} instance * @throws NullPointerException - * if {@code stop} is null + * if {@code stop} is {@code null} * @see ReactiveX operators documentation: Repeat */ @BackpressureSupport(BackpressureKind.FULL) @@ -4010,49 +4819,50 @@ public final Flowable repeatUntil(@NonNull BooleanSupplier stop) { } /** - * Returns a Flowable that emits the same values as the source Publisher with the exception of an + * Returns a {@link Flowable} that emits the same values as the current {@code Maybe} with the exception of an * {@code onComplete}. An {@code onComplete} notification from the source will result in the emission of - * a {@code void} item to the Publisher provided as an argument to the {@code notificationHandler} - * function. If that Publisher calls {@code onComplete} or {@code onError} then {@code repeatWhen} will - * call {@code onComplete} or {@code onError} on the child subscription. Otherwise, this Publisher will - * resubscribe to the source Publisher. + * a {@code void} item to the {@code Flowable} provided as an argument to the {@code notificationHandler} + * function. If that {@link Publisher} calls {@code onComplete} or {@code onError} then {@code repeatWhen} will + * call {@code onComplete} or {@code onError} on the child observer. Otherwise, this operator will + * resubscribe to the current {@code Maybe}. *

- * + * *

*
Backpressure:
*
The operator honors downstream backpressure and expects the source {@code Publisher} to honor backpressure as well. - * If this expectation is violated, the operator may throw an {@code IllegalStateException}.
+ * If this expectation is violated, the operator may throw an {@link IllegalStateException}.
*
Scheduler:
*
{@code repeatWhen} does not operate by default on a particular {@link Scheduler}.
*
* * @param handler - * receives a Publisher of notifications with which a user can complete or error, aborting the repeat. - * @return the source Publisher modified with repeat logic + * receives a {@code Publisher} of notifications with which a user can complete or error, aborting the repeat. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code handler} is {@code null} * @see ReactiveX operators documentation: Repeat */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable repeatWhen(@NonNull Function, ? extends Publisher> handler) { + public final Flowable repeatWhen(@NonNull Function, @NonNull ? extends Publisher<@NonNull ?>> handler) { return toFlowable().repeatWhen(handler); } /** - * Returns a Maybe that mirrors the source Maybe, resubscribing to it if it calls {@code onError} + * Returns a {@code Maybe} that mirrors the current {@code Maybe}, resubscribing to it if it calls {@code onError} * (infinite retry count). *

- * + * *

- * If the source Maybe calls {@link MaybeObserver#onError}, this method will resubscribe to the source - * Maybe rather than propagating the {@code onError} call. + * If the current {@code Maybe} calls {@link MaybeObserver#onError}, this operator will resubscribe to the current + * {@code Maybe} rather than propagating the {@code onError} call. *

*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
* - * @return the new Maybe instance + * @return the new {@code Maybe} instance * @see ReactiveX operators documentation: Retry */ @CheckReturnValue @@ -4063,10 +4873,10 @@ public final Maybe retry() { } /** - * Returns a Maybe that mirrors the source Maybe, resubscribing to it if it calls {@code onError} - * and the predicate returns true for that specific exception and retry count. + * Returns a {@code Maybe} that mirrors the current {@code Maybe}, resubscribing to it if it calls {@code onError} + * and the predicate returns {@code true} for that specific exception and retry count. *

- * + * *

*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
@@ -4075,7 +4885,8 @@ public final Maybe retry() { * @param predicate * the predicate that determines if a resubscription may happen in case of a specific exception * and retry count - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @see #retry() * @see ReactiveX operators documentation: Retry */ @@ -4087,41 +4898,45 @@ public final Maybe retry(@NonNull BiPredicate - * + * *

- * If the source Maybe calls {@link MaybeObserver#onError}, this method will resubscribe to the source - * Maybe for a maximum of {@code count} resubscriptions rather than propagating the + * If the current {@code Maybe} calls {@link MaybeObserver#onError}, this operator will resubscribe to the current + * {@code Maybe} for a maximum of {@code count} resubscriptions rather than propagating the * {@code onError} call. *

*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
* - * @param count - * the number of times to resubscribe if the current Maybe fails - * @return the new Maybe instance + * @param times + * the number of times to resubscribe if the current {@code Maybe} fails + * @return the new {@code Maybe} instance + * @throws IllegalArgumentException if {@code times} is negative * @see ReactiveX operators documentation: Retry */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Maybe retry(long count) { - return retry(count, Functions.alwaysTrue()); + public final Maybe retry(long times) { + return retry(times, Functions.alwaysTrue()); } /** - * Retries at most times or until the predicate returns false, whichever happens first. - * + * Retries at most {@code times} or until the predicate returns {@code false}, whichever happens first. + *

+ * *

*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
- * @param times the number of times to resubscribe if the current Maybe fails - * @param predicate the predicate called with the failure Throwable and should return true to trigger a retry. - * @return the new Maybe instance + * @param times the number of times to resubscribe if the current {@code Maybe} fails + * @param predicate the predicate called with the failure {@link Throwable} and should return {@code true} to trigger a retry. + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code predicate} is {@code null} + * @throws IllegalArgumentException if {@code times} is negative */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -4131,14 +4946,17 @@ public final Maybe retry(long times, @NonNull Predicate pr } /** - * Retries the current Maybe if it fails and the predicate returns true. + * Retries the current {@code Maybe} if it fails and the predicate returns {@code true}. + *

+ * *

*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
* - * @param predicate the predicate that receives the failure Throwable and should return true to trigger a retry. - * @return the new Maybe instance + * @param predicate the predicate that receives the failure {@link Throwable} and should return {@code true} to trigger a retry. + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code predicate} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -4148,13 +4966,16 @@ public final Maybe retry(@NonNull Predicate predicate) { } /** - * Retries until the given stop function returns true. + * Retries until the given stop function returns {@code true}. + *

+ * *

*
Scheduler:
*
{@code retryUntil} does not operate by default on a particular {@link Scheduler}.
*
- * @param stop the function that should return true to stop retrying - * @return the new Maybe instance + * @param stop the function that should return {@code true} to stop retrying + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code stop} is {@code null} */ @CheckReturnValue @NonNull @@ -4165,14 +4986,14 @@ public final Maybe retryUntil(@NonNull BooleanSupplier stop) { } /** - * Returns a Maybe that emits the same values as the source Maybe with the exception of an + * Returns a {@code Maybe} that emits the same values as the current {@code Maybe} with the exception of an * {@code onError}. An {@code onError} notification from the source will result in the emission of a - * {@link Throwable} item to the Publisher provided as an argument to the {@code notificationHandler} - * function. If that Publisher calls {@code onComplete} or {@code onError} then {@code retry} will call - * {@code onComplete} or {@code onError} on the child subscription. Otherwise, this Publisher will - * resubscribe to the source Publisher. + * {@link Throwable} item to the {@link Flowable} provided as an argument to the {@code notificationHandler} + * function. If the returned {@link Publisher} calls {@code onComplete} or {@code onError} then {@code retry} will call + * {@code onComplete} or {@code onError} on the child subscription. Otherwise, this operator will + * resubscribe to the current {@code Maybe}. *

- * + * *

* Example: * @@ -4205,7 +5026,7 @@ public final Maybe retryUntil(@NonNull BooleanSupplier stop) { * Note that the inner {@code Publisher} returned by the handler function should signal * either {@code onNext}, {@code onError} or {@code onComplete} in response to the received * {@code Throwable} to indicate the operator should retry or terminate. If the upstream to - * the operator is asynchronous, signalling onNext followed by onComplete immediately may + * the operator is asynchronous, signalling {@code onNext} followed by {@code onComplete} immediately may * result in the sequence to be completed immediately. Similarly, if this inner * {@code Publisher} signals {@code onError} or {@code onComplete} while the upstream is * active, the sequence is terminated with the same signal immediately. @@ -4232,33 +5053,182 @@ public final Maybe retryUntil(@NonNull BooleanSupplier stop) { *

* * @param handler - * receives a Publisher of notifications with which a user can complete or error, aborting the + * receives a {@code Publisher} of notifications with which a user can complete or error, aborting the * retry - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code handler} is {@code null} * @see ReactiveX operators documentation: Retry */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final Maybe retryWhen( - @NonNull Function, ? extends Publisher> handler) { + @NonNull Function, @NonNull ? extends Publisher<@NonNull ?>> handler) { return toFlowable().retryWhen(handler).singleElement(); } /** - * Subscribes to a Maybe and ignores {@code onSuccess} and {@code onComplete} emissions. + * Wraps the given {@link MaybeObserver}, catches any {@link RuntimeException}s thrown by its + * {@link MaybeObserver#onSubscribe(Disposable)}, {@link MaybeObserver#onSuccess(Object)}, + * {@link MaybeObserver#onError(Throwable)} or {@link MaybeObserver#onComplete()} methods + * and routes those to the global error handler via {@link RxJavaPlugins#onError(Throwable)}. + *

+ * By default, the {@code Maybe} protocol forbids the {@code onXXX} methods to throw, but some + * {@code MaybeObserver} implementation may do it anyway, causing undefined behavior in the + * upstream. This method and the underlying safe wrapper ensures such misbehaving consumers don't + * disrupt the protocol. + *

+ *
Scheduler:
+ *
{@code safeSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param observer the potentially misbehaving {@code MaybeObserver} + * @throws NullPointerException if {@code observer} is {@code null} + * @see #subscribe(Consumer,Consumer, Action) + * @since 3.0.0 + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void safeSubscribe(@NonNull MaybeObserver observer) { + Objects.requireNonNull(observer, "observer is null"); + subscribe(new SafeMaybeObserver<>(observer)); + } + + /** + * Returns a {@link Flowable} which first runs the other {@link CompletableSource} + * then the current {@code Maybe} if the other completed normally. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Flowable} honors the backpressure of the downstream consumer.
+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code CompletableSource} to run first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.FULL) + public final Flowable startWith(@NonNull CompletableSource other) { + Objects.requireNonNull(other, "other is null"); + return Flowable.concat(Completable.wrap(other).toFlowable(), toFlowable()); + } + + /** + * Returns a {@link Flowable} which first runs the other {@link SingleSource} + * then the current {@code Maybe} if the other succeeded normally. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Flowable} honors the backpressure of the downstream consumer.
+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code SingleSource} to run first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.FULL) + public final Flowable startWith(@NonNull SingleSource other) { + Objects.requireNonNull(other, "other is null"); + return Flowable.concat(Single.wrap(other).toFlowable(), toFlowable()); + } + + /** + * Returns a {@link Flowable} which first runs the other {@link MaybeSource} + * then the current {@code Maybe} if the other succeeded or completed normally. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Flowable} honors the backpressure of the downstream consumer.
+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code MaybeSource} to run first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.FULL) + public final Flowable startWith(@NonNull MaybeSource other) { + Objects.requireNonNull(other, "other is null"); + return Flowable.concat(Maybe.wrap(other).toFlowable(), toFlowable()); + } + + /** + * Returns an {@link Observable} which first delivers the events + * of the other {@link ObservableSource} then runs the current {@code Maybe}. + *

+ * + *

+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code ObservableSource} to run first + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final Observable startWith(@NonNull ObservableSource other) { + Objects.requireNonNull(other, "other is null"); + return Observable.wrap(other).concatWith(this.toObservable()); + } + + /** + * Returns a {@link Flowable} which first delivers the events + * of the other {@link Publisher} then runs the current {@code Maybe}. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Flowable} honors the backpressure of the downstream consumer + * and expects the other {@code Publisher} to honor it as well.
+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code Publisher} to run first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @BackpressureSupport(BackpressureKind.FULL) + @SchedulerSupport(SchedulerSupport.NONE) + public final Flowable startWith(@NonNull Publisher other) { + Objects.requireNonNull(other, "other is null"); + return toFlowable().startWith(other); + } + + /** + * Subscribes to a {@code Maybe} and ignores {@code onSuccess} and {@code onComplete} emissions. *

- * If the Maybe emits an error, it is wrapped into an + * If the {@code Maybe} emits an error, it is wrapped into an * {@link io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException OnErrorNotImplementedException} - * and routed to the RxJavaPlugins.onError handler. + * and routed to the {@link RxJavaPlugins#onError(Throwable)} handler. *

*
Scheduler:
*
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@link Disposable} reference with which the caller can stop receiving items before - * the Maybe has finished sending them + * @return the new {@link Disposable} instance that can be used for disposing the subscription at any time * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, Action, DisposableContainer) */ @SchedulerSupport(SchedulerSupport.NONE) @NonNull @@ -4267,23 +5237,23 @@ public final Disposable subscribe() { } /** - * Subscribes to a Maybe and provides a callback to handle the items it emits. + * Subscribes to a {@code Maybe} and provides a callback to handle the items it emits. *

- * If the Maybe emits an error, it is wrapped into an + * If the {@code Maybe} emits an error, it is wrapped into an * {@link io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException OnErrorNotImplementedException} - * and routed to the RxJavaPlugins.onError handler. + * and routed to the {@link RxJavaPlugins#onError(Throwable)} handler. *

*
Scheduler:
*
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
* * @param onSuccess - * the {@code Consumer} you have designed to accept a success value from the Maybe - * @return a {@link Disposable} reference with which the caller can stop receiving items before - * the Maybe has finished sending them + * the {@code Consumer} you have designed to accept a success value from the {@code Maybe} + * @return the new {@link Disposable} instance that can be used for disposing the subscription at any time * @throws NullPointerException - * if {@code onSuccess} is null + * if {@code onSuccess} is {@code null} * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, Action, DisposableContainer) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -4293,7 +5263,7 @@ public final Disposable subscribe(@NonNull Consumer onSuccess) { } /** - * Subscribes to a Maybe and provides callbacks to handle the items it emits and any error + * Subscribes to a {@code Maybe} and provides callbacks to handle the items it emits and any error * notification it issues. *
*
Scheduler:
@@ -4301,16 +5271,16 @@ public final Disposable subscribe(@NonNull Consumer onSuccess) { *
* * @param onSuccess - * the {@code Consumer} you have designed to accept a success value from the Maybe + * the {@code Consumer} you have designed to accept a success value from the {@code Maybe} * @param onError * the {@code Consumer} you have designed to accept any error notification from the - * Maybe - * @return a {@link Disposable} reference with which the caller can stop receiving items before - * the Maybe has finished sending them - * @see ReactiveX operators documentation: Subscribe + * {@code Maybe} + * @return the new {@link Disposable} instance that can be used for disposing the subscription at any time * @throws NullPointerException - * if {@code onSuccess} is null, or - * if {@code onError} is null + * if {@code onSuccess} is {@code null}, or + * if {@code onError} is {@code null} + * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, Action, DisposableContainer) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -4320,7 +5290,7 @@ public final Disposable subscribe(@NonNull Consumer onSuccess, @NonNu } /** - * Subscribes to a Maybe and provides callbacks to handle the items it emits and any error or + * Subscribes to a {@code Maybe} and provides callbacks to handle the items it emits and any error or * completion notification it issues. *
*
Scheduler:
@@ -4328,20 +5298,19 @@ public final Disposable subscribe(@NonNull Consumer onSuccess, @NonNu *
* * @param onSuccess - * the {@code Consumer} you have designed to accept a success value from the Maybe + * the {@code Consumer} you have designed to accept a success value from the {@code Maybe} * @param onError * the {@code Consumer} you have designed to accept any error notification from the - * Maybe + * {@code Maybe} * @param onComplete - * the {@code Action} you have designed to accept a completion notification from the - * Maybe - * @return a {@link Disposable} reference with which the caller can stop receiving items before - * the Maybe has finished sending them + * the {@link Action} you have designed to accept a completion notification from the + * {@code Maybe} + * @return the new {@link Disposable} instance that can be used for disposing the subscription at any time * @throws NullPointerException - * if {@code onSuccess} is null, or - * if {@code onError} is null, or - * if {@code onComplete} is null + * if {@code onSuccess}, {@code onError} or + * {@code onComplete} is {@code null} * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, Action, DisposableContainer) */ @CheckReturnValue @NonNull @@ -4354,6 +5323,47 @@ public final Disposable subscribe(@NonNull Consumer onSuccess, @NonNu return subscribeWith(new MaybeCallbackObserver<>(onSuccess, onError, onComplete)); } + /** + * Wraps the given onXXX callbacks into a {@link Disposable} {@link MaybeObserver}, + * adds it to the given {@link DisposableContainer} and ensures, that if the upstream + * terminates or this particular {@code Disposable} is disposed, the {@code MaybeObserver} is removed + * from the given composite. + *

+ * The {@code MaybeObserver} will be removed after the callback for the terminal event has been invoked. + *

+ *
Scheduler:
+ *
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param onSuccess the callback for upstream items + * @param onError the callback for an upstream error + * @param onComplete the callback for an upstream completion without any value or error + * @param container the {@code DisposableContainer} (such as {@link CompositeDisposable}) to add and remove the + * created {@code Disposable} {@code MaybeObserver} + * @return the {@code Disposable} that allows disposing the particular subscription. + * @throws NullPointerException + * if {@code onSuccess}, {@code onError}, + * {@code onComplete} or {@code container} is {@code null} + * @since 3.1.0 + */ + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Disposable subscribe( + @NonNull Consumer onSuccess, + @NonNull Consumer onError, + @NonNull Action onComplete, + @NonNull DisposableContainer container) { + Objects.requireNonNull(onSuccess, "onSuccess is null"); + Objects.requireNonNull(onError, "onError is null"); + Objects.requireNonNull(onComplete, "onComplete is null"); + Objects.requireNonNull(container, "container is null"); + + DisposableAutoReleaseMultiObserver observer = new DisposableAutoReleaseMultiObserver<>( + container, onSuccess, onError, onComplete); + container.add(observer); + subscribe(observer); + return observer; + } + @SchedulerSupport(SchedulerSupport.NONE) @Override public final void subscribe(@NonNull MaybeObserver observer) { @@ -4380,22 +5390,23 @@ public final void subscribe(@NonNull MaybeObserver observer) { *

There is no need to call any of the plugin hooks on the current {@code Maybe} instance or * the {@code MaybeObserver}; all hooks and basic safeguards have been * applied by {@link #subscribe(MaybeObserver)} before this method gets called. - * @param observer the MaybeObserver to handle, not null + * @param observer the {@code MaybeObserver} to handle, not {@code null} */ protected abstract void subscribeActual(@NonNull MaybeObserver observer); /** - * Asynchronously subscribes subscribers to this Maybe on the specified {@link Scheduler}. + * Asynchronously subscribes subscribers to this {@code Maybe} on the specified {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
you specify which {@link Scheduler} this operator will use.
+ *
you specify which {@code Scheduler} this operator will use.
*
* * @param scheduler - * the {@link Scheduler} to perform subscription actions on - * @return the new Maybe instance that its subscriptions happen on the specified {@link Scheduler} + * the {@code Scheduler} to perform subscription actions on + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: SubscribeOn * @see RxJava Threading Examples * @see #observeOn @@ -4409,8 +5420,8 @@ public final Maybe subscribeOn(@NonNull Scheduler scheduler) { } /** - * Subscribes a given MaybeObserver (subclass) to this Maybe and returns the given - * MaybeObserver as is. + * Subscribes a given {@link MaybeObserver} (subclass) to this {@code Maybe} and returns the given + * {@code MaybeObserver} as is. *

Usage example: *


      * Maybe<Integer> source = Maybe.just(1);
@@ -4426,10 +5437,10 @@ public final Maybe subscribeOn(@NonNull Scheduler scheduler) {
      *  
Scheduler:
*
{@code subscribeWith} does not operate by default on a particular {@link Scheduler}.
*
- * @param the type of the MaybeObserver to use and return - * @param observer the MaybeObserver (subclass) to use and return, not null - * @return the input {@code subscriber} - * @throws NullPointerException if {@code subscriber} is null + * @param the type of the {@code MaybeObserver} to use and return + * @param observer the {@code MaybeObserver} (subclass) to use and return, not {@code null} + * @return the input {@code observer} + * @throws NullPointerException if {@code observer} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -4440,19 +5451,19 @@ public final Maybe subscribeOn(@NonNull Scheduler scheduler) { } /** - * Returns a Maybe that emits the items emitted by the source Maybe or the items of an alternate - * MaybeSource if the current Maybe is empty. + * Returns a {@code Maybe} that emits the items emitted by the current {@code Maybe} or the items of an alternate + * {@link MaybeSource} if the current {@code Maybe} is empty. *

- * + * *

*
Scheduler:
*
{@code switchIfEmpty} does not operate by default on a particular {@link Scheduler}.
*
* * @param other - * the alternate MaybeSource to subscribe to if the main does not emit any items - * @return a Maybe that emits the items emitted by the source Maybe or the items of an - * alternate MaybeSource if the source Maybe is empty. + * the alternate {@code MaybeSource} to subscribe to if the main does not emit any items + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code other} is {@code null} */ @CheckReturnValue @NonNull @@ -4463,19 +5474,19 @@ public final Maybe switchIfEmpty(@NonNull MaybeSource other) { } /** - * Returns a Single that emits the items emitted by the source Maybe or the item of an alternate - * SingleSource if the current Maybe is empty. + * Returns a {@link Single} that emits the items emitted by the current {@code Maybe} or the item of an alternate + * {@link SingleSource} if the current {@code Maybe} is empty. *

- * + * *

*
Scheduler:
*
{@code switchIfEmpty} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.1.4 - experimental * @param other - * the alternate SingleSource to subscribe to if the main does not emit any items - * @return a Single that emits the items emitted by the source Maybe or the item of an - * alternate SingleSource if the source Maybe is empty. + * the alternate {@code SingleSource} to subscribe to if the main does not emit any items + * @return the new {@code Single} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -4487,36 +5498,37 @@ public final Single switchIfEmpty(@NonNull SingleSource other) { } /** - * Returns a Maybe that emits the items emitted by the source Maybe until a second MaybeSource + * Returns a {@code Maybe} that emits the items emitted by the current {@code Maybe} until a second {@link MaybeSource} * emits an item. *

- * + * *

*
Scheduler:
*
{@code takeUntil} does not operate by default on a particular {@link Scheduler}.
*
* * @param other - * the MaybeSource whose first emitted item will cause {@code takeUntil} to stop emitting items - * from the source Maybe + * the {@code MaybeSource} whose first emitted item will cause {@code takeUntil} to stop emitting items + * from the current {@code Maybe} * @param * the type of items emitted by {@code other} - * @return a Maybe that emits the items emitted by the source Maybe until such time as {@code other} emits its first item + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: TakeUntil */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe takeUntil(@NonNull MaybeSource other) { + public final <@NonNull U> Maybe takeUntil(@NonNull MaybeSource other) { Objects.requireNonNull(other, "other is null"); return RxJavaPlugins.onAssembly(new MaybeTakeUntilMaybe<>(this, other)); } /** - * Returns a Maybe that emits the item emitted by the source Maybe until a second Publisher + * Returns a {@code Maybe} that emits the item emitted by the current {@code Maybe} until a second {@link Publisher} * emits an item. *

- * + * *

*
Backpressure:
*
The {@code Publisher} is consumed in an unbounded fashion and is cancelled after the first item @@ -4526,28 +5538,255 @@ public final Maybe takeUntil(@NonNull MaybeSource other) { *
* * @param other - * the Publisher whose first emitted item will cause {@code takeUntil} to stop emitting items - * from the source Publisher + * the {@code Publisher} whose first emitted item will cause {@code takeUntil} to stop emitting items + * from the source {@code Publisher} * @param * the type of items emitted by {@code other} - * @return a Maybe that emits the items emitted by the source Maybe until such time as {@code other} emits its first item + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: TakeUntil */ @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe takeUntil(@NonNull Publisher other) { + public final <@NonNull U> Maybe takeUntil(@NonNull Publisher other) { Objects.requireNonNull(other, "other is null"); return RxJavaPlugins.onAssembly(new MaybeTakeUntilPublisher<>(this, other)); } /** - * Returns a Maybe that mirrors the source Maybe but applies a timeout policy for each emitted + * Measures the time (in milliseconds) between the subscription and success item emission + * of the current {@code Maybe} and signals it as a tuple ({@link Timed}) + * success value. + *

+ * + *

+ * If the current {@code Maybe} is empty or fails, the resulting {@code Maybe} will + * pass along the signals to the downstream. To measure the time to termination, + * use {@link #materialize()} and apply {@link Single#timeInterval()}. + *

+ *
Scheduler:
+ *
{@code timeInterval} uses the {@code computation} {@link Scheduler} + * for determining the current time upon subscription and upon receiving the + * success item from the current {@code Maybe}.
+ *
+ * @return the new {@code Maybe} instance + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.COMPUTATION) + public final Maybe> timeInterval() { + return timeInterval(TimeUnit.MILLISECONDS, Schedulers.computation()); + } + + /** + * Measures the time (in milliseconds) between the subscription and success item emission + * of the current {@code Maybe} and signals it as a tuple ({@link Timed}) + * success value. + *

+ * + *

+ * If the current {@code Maybe} is empty or fails, the resulting {@code Maybe} will + * pass along the signals to the downstream. To measure the time to termination, + * use {@link #materialize()} and apply {@link Single#timeInterval(Scheduler)}. + *

+ *
Scheduler:
+ *
{@code timeInterval} uses the provided {@link Scheduler} + * for determining the current time upon subscription and upon receiving the + * success item from the current {@code Maybe}.
+ *
+ * @param scheduler the {@code Scheduler} used for providing the current time + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code scheduler} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.CUSTOM) + public final Maybe> timeInterval(@NonNull Scheduler scheduler) { + return timeInterval(TimeUnit.MILLISECONDS, scheduler); + } + + /** + * Measures the time between the subscription and success item emission + * of the current {@code Maybe} and signals it as a tuple ({@link Timed}) + * success value. + *

+ * + *

+ * If the current {@code Maybe} is empty or fails, the resulting {@code Maybe} will + * pass along the signals to the downstream. To measure the time to termination, + * use {@link #materialize()} and apply {@link Single#timeInterval(TimeUnit)}. + *

+ *
Scheduler:
+ *
{@code timeInterval} uses the {@code computation} {@link Scheduler} + * for determining the current time upon subscription and upon receiving the + * success item from the current {@code Maybe}.
+ *
+ * @param unit the time unit for measurement + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.COMPUTATION) + public final Maybe> timeInterval(@NonNull TimeUnit unit) { + return timeInterval(unit, Schedulers.computation()); + } + + /** + * Measures the time between the subscription and success item emission + * of the current {@code Maybe} and signals it as a tuple ({@link Timed}) + * success value. + *

+ * + *

+ * If the current {@code Maybe} is empty or fails, the resulting {@code Maybe} will + * pass along the signals to the downstream. To measure the time to termination, + * use {@link #materialize()} and apply {@link Single#timeInterval(TimeUnit, Scheduler)}. + *

+ *
Scheduler:
+ *
{@code timeInterval} uses the provided {@link Scheduler} + * for determining the current time upon subscription and upon receiving the + * success item from the current {@code Maybe}.
+ *
+ * @param unit the time unit for measurement + * @param scheduler the {@code Scheduler} used for providing the current time + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.CUSTOM) + public final Maybe> timeInterval(@NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + return RxJavaPlugins.onAssembly(new MaybeTimeInterval<>(this, unit, scheduler, true)); + } + + /** + * Combines the success value from the current {@code Maybe} with the current time (in milliseconds) of + * its reception, using the {@code computation} {@link Scheduler} as time source, + * then signals them as a {@link Timed} instance. + *

+ * + *

+ * If the current {@code Maybe} is empty or fails, the resulting {@code Maybe} will + * pass along the signals to the downstream. To measure the time to termination, + * use {@link #materialize()} and apply {@link Single#timestamp()}. + *

+ *
Scheduler:
+ *
{@code timestamp} uses the {@code computation} {@code Scheduler} + * for determining the current time upon receiving the + * success item from the current {@code Maybe}.
+ *
+ * @return the new {@code Maybe} instance + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.COMPUTATION) + public final Maybe> timestamp() { + return timestamp(TimeUnit.MILLISECONDS, Schedulers.computation()); + } + + /** + * Combines the success value from the current {@code Maybe} with the current time (in milliseconds) of + * its reception, using the given {@link Scheduler} as time source, + * then signals them as a {@link Timed} instance. + *

+ * + *

+ * If the current {@code Maybe} is empty or fails, the resulting {@code Maybe} will + * pass along the signals to the downstream. To measure the time to termination, + * use {@link #materialize()} and apply {@link Single#timestamp(Scheduler)}. + *

+ *
Scheduler:
+ *
{@code timestamp} uses the provided {@code Scheduler} + * for determining the current time upon receiving the + * success item from the current {@code Maybe}.
+ *
+ * @param scheduler the {@code Scheduler} used for providing the current time + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code scheduler} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.CUSTOM) + public final Maybe> timestamp(@NonNull Scheduler scheduler) { + return timestamp(TimeUnit.MILLISECONDS, scheduler); + } + + /** + * Combines the success value from the current {@code Maybe} with the current time of + * its reception, using the {@code computation} {@link Scheduler} as time source, + * then signals it as a {@link Timed} instance. + *

+ * + *

+ * If the current {@code Maybe} is empty or fails, the resulting {@code Maybe} will + * pass along the signals to the downstream. To measure the time to termination, + * use {@link #materialize()} and apply {@link Single#timestamp(TimeUnit)}. + *

+ *
Scheduler:
+ *
{@code timestamp} uses the {@code computation} {@code Scheduler}, + * for determining the current time upon receiving the + * success item from the current {@code Maybe}.
+ *
+ * @param unit the time unit for measurement + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.COMPUTATION) + public final Maybe> timestamp(@NonNull TimeUnit unit) { + return timestamp(unit, Schedulers.computation()); + } + + /** + * Combines the success value from the current {@code Maybe} with the current time of + * its reception, using the given {@link Scheduler} as time source, + * then signals it as a {@link Timed} instance. + *

+ * + *

+ * If the current {@code Maybe} is empty or fails, the resulting {@code Maybe} will + * pass along the signals to the downstream. To measure the time to termination, + * use {@link #materialize()} and apply {@link Single#timestamp(TimeUnit, Scheduler)}. + *

+ *
Scheduler:
+ *
{@code timestamp} uses the provided {@code Scheduler}, + * which is used for determining the current time upon receiving the + * success item from the current {@code Maybe}.
+ *
+ * @param unit the time unit for measurement + * @param scheduler the {@code Scheduler} used for providing the current time + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.CUSTOM) + public final Maybe> timestamp(@NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + return RxJavaPlugins.onAssembly(new MaybeTimeInterval<>(this, unit, scheduler, false)); + } + + /** + * Returns a {@code Maybe} that mirrors the current {@code Maybe} but applies a timeout policy for each emitted * item. If the next item isn't emitted within the specified timeout duration starting from its predecessor, - * the resulting Maybe terminates and notifies MaybeObservers of a {@code TimeoutException}. + * the resulting {@code Maybe} terminates and notifies {@link MaybeObserver}s of a {@link TimeoutException}. *

- * + * *

*
Scheduler:
*
This version of {@code timeout} operates by default on the {@code computation} {@link Scheduler}.
@@ -4555,24 +5794,25 @@ public final Maybe takeUntil(@NonNull Publisher other) { * * @param timeout * maximum duration between emitted items before a timeout occurs - * @param timeUnit + * @param unit * the unit of time that applies to the {@code timeout} argument. - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Maybe timeout(long timeout, @NonNull TimeUnit timeUnit) { - return timeout(timeout, timeUnit, Schedulers.computation()); + public final Maybe timeout(long timeout, @NonNull TimeUnit unit) { + return timeout(timeout, unit, Schedulers.computation()); } /** - * Returns a Maybe that mirrors the source Maybe but applies a timeout policy for each emitted + * Returns a {@code Maybe} that mirrors the current {@code Maybe} but applies a timeout policy for each emitted * item. If the next item isn't emitted within the specified timeout duration starting from its predecessor, - * the source MaybeSource is disposed and resulting Maybe begins instead to mirror a fallback MaybeSource. + * the current {@code Maybe} is disposed and resulting {@code Maybe} begins instead to mirror a fallback {@link MaybeSource}. *

- * + * *

*
Scheduler:
*
This version of {@code timeout} operates by default on the {@code computation} {@link Scheduler}.
@@ -4580,96 +5820,102 @@ public final Maybe timeout(long timeout, @NonNull TimeUnit timeUnit) { * * @param timeout * maximum duration between items before a timeout occurs - * @param timeUnit + * @param unit * the unit of time that applies to the {@code timeout} argument * @param fallback - * the fallback MaybeSource to use in case of a timeout - * @return the new Maybe instance + * the fallback {@code MaybeSource} to use in case of a timeout + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code unit} or {@code fallback} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.COMPUTATION) - public final Maybe timeout(long timeout, @NonNull TimeUnit timeUnit, @NonNull MaybeSource fallback) { + public final Maybe timeout(long timeout, @NonNull TimeUnit unit, @NonNull MaybeSource fallback) { Objects.requireNonNull(fallback, "fallback is null"); - return timeout(timeout, timeUnit, Schedulers.computation(), fallback); + return timeout(timeout, unit, Schedulers.computation(), fallback); } /** - * Returns a Maybe that mirrors the source Maybe but applies a timeout policy for each emitted - * item using a specified Scheduler. If the next item isn't emitted within the specified timeout duration - * starting from its predecessor, the source MaybeSource is disposed and resulting Maybe begins instead - * to mirror a fallback MaybeSource. + * Returns a {@code Maybe} that mirrors the current {@code Maybe} but applies a timeout policy for each emitted + * item using a specified {@link Scheduler}. If the next item isn't emitted within the specified timeout duration + * starting from its predecessor, the current {@code Maybe} is disposed and resulting {@code Maybe} begins instead + * to mirror a fallback {@link MaybeSource}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param timeout * maximum duration between items before a timeout occurs - * @param timeUnit + * @param unit * the unit of time that applies to the {@code timeout} argument * @param fallback - * the MaybeSource to use as the fallback in case of a timeout + * the {@code MaybeSource} to use as the fallback in case of a timeout * @param scheduler - * the {@link Scheduler} to run the timeout timers on - * @return the new Maybe instance + * the {@code Scheduler} to run the timeout timers on + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code fallback}, {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Maybe timeout(long timeout, @NonNull TimeUnit timeUnit, @NonNull Scheduler scheduler, @NonNull MaybeSource fallback) { + public final Maybe timeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull MaybeSource fallback) { Objects.requireNonNull(fallback, "fallback is null"); - return timeout(timer(timeout, timeUnit, scheduler), fallback); + return timeout(timer(timeout, unit, scheduler), fallback); } /** - * Returns a Maybe that mirrors the source Maybe but applies a timeout policy for each emitted - * item, where this policy is governed on a specified Scheduler. If the next item isn't emitted within the - * specified timeout duration starting from its predecessor, the resulting Maybe terminates and - * notifies MaybeObservers of a {@code TimeoutException}. + * Returns a {@code Maybe} that mirrors the current {@code Maybe} but applies a timeout policy for each emitted + * item, where this policy is governed on a specified {@link Scheduler}. If the next item isn't emitted within the + * specified timeout duration starting from its predecessor, the resulting {@code Maybe} terminates and + * notifies {@link MaybeObserver}s of a {@link TimeoutException}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param timeout * maximum duration between items before a timeout occurs - * @param timeUnit + * @param unit * the unit of time that applies to the {@code timeout} argument * @param scheduler - * the Scheduler to run the timeout timers on - * @return the new Maybe instance + * the {@code Scheduler} to run the timeout timers on + * @return the new {@code Maybe} instance * @see ReactiveX operators documentation: Timeout + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Maybe timeout(long timeout, @NonNull TimeUnit timeUnit, @NonNull Scheduler scheduler) { - return timeout(timer(timeout, timeUnit, scheduler)); + public final Maybe timeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + return timeout(timer(timeout, unit, scheduler)); } /** * If the current {@code Maybe} didn't signal an event before the {@code timeoutIndicator} {@link MaybeSource} signals, a * {@link TimeoutException} is signaled instead. + *

+ * *

*
Scheduler:
*
{@code timeout} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type of the - * @param timeoutIndicator the {@code MaybeSource} that indicates the timeout by signaling onSuccess - * or onComplete. - * @return the new Maybe instance + * @param timeoutIndicator the {@code MaybeSource} that indicates the timeout by signaling {@code onSuccess} + * or {@code onComplete}. + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code timeoutIndicator} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe timeout(@NonNull MaybeSource timeoutIndicator) { + public final <@NonNull U> Maybe timeout(@NonNull MaybeSource timeoutIndicator) { Objects.requireNonNull(timeoutIndicator, "timeoutIndicator is null"); return RxJavaPlugins.onAssembly(new MaybeTimeoutMaybe<>(this, timeoutIndicator, null)); } @@ -4678,6 +5924,8 @@ public final Maybe timeout(@NonNull MaybeSource timeoutIndicator) { * If the current {@code Maybe} didn't signal an event before the {@code timeoutIndicator} {@link MaybeSource} signals, * the current {@code Maybe} is disposed and the {@code fallback} {@code MaybeSource} subscribed to * as a continuation. + *

+ * *

*
Scheduler:
*
{@code timeout} does not operate by default on a particular {@link Scheduler}.
@@ -4686,12 +5934,13 @@ public final Maybe timeout(@NonNull MaybeSource timeoutIndicator) { * @param timeoutIndicator the {@code MaybeSource} that indicates the timeout by signaling {@code onSuccess} * or {@code onComplete}. * @param fallback the {@code MaybeSource} that is subscribed to if the current {@code Maybe} times out - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code timeoutIndicator} or {@code fallback} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe timeout(@NonNull MaybeSource timeoutIndicator, @NonNull MaybeSource fallback) { + public final <@NonNull U> Maybe timeout(@NonNull MaybeSource timeoutIndicator, @NonNull MaybeSource fallback) { Objects.requireNonNull(timeoutIndicator, "timeoutIndicator is null"); Objects.requireNonNull(fallback, "fallback is null"); return RxJavaPlugins.onAssembly(new MaybeTimeoutMaybe<>(this, timeoutIndicator, fallback)); @@ -4700,34 +5949,39 @@ public final Maybe timeout(@NonNull MaybeSource timeoutIndicator, @Non /** * If the current {@code Maybe} source didn't signal an event before the {@code timeoutIndicator} {@link Publisher} signals, a * {@link TimeoutException} is signaled instead. + *

+ * *

*
Backpressure:
- *
The {@code timeoutIndicator} {@link Publisher} is consumed in an unbounded manner and + *
The {@code timeoutIndicator} {@code Publisher} is consumed in an unbounded manner and * is cancelled after its first item.
*
Scheduler:
*
{@code timeout} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type of the - * @param timeoutIndicator the {@code MaybeSource} that indicates the timeout by signaling {@code onSuccess} + * @param timeoutIndicator the {@code Publisher} that indicates the timeout by signaling {@code onSuccess} * or {@code onComplete}. - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code timeoutIndicator} is {@code null} */ @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe timeout(@NonNull Publisher timeoutIndicator) { + public final <@NonNull U> Maybe timeout(@NonNull Publisher timeoutIndicator) { Objects.requireNonNull(timeoutIndicator, "timeoutIndicator is null"); return RxJavaPlugins.onAssembly(new MaybeTimeoutPublisher<>(this, timeoutIndicator, null)); } /** * If the current {@code Maybe} didn't signal an event before the {@code timeoutIndicator} {@link Publisher} signals, - * the current {@code Maybe} is disposed and the {@code fallback} {@code MaybeSource} subscribed to + * the current {@code Maybe} is disposed and the {@code fallback} {@link MaybeSource} subscribed to * as a continuation. + *

+ * *

*
Backpressure:
- *
The {@code timeoutIndicator} {@link Publisher} is consumed in an unbounded manner and + *
The {@code timeoutIndicator} {@code Publisher} is consumed in an unbounded manner and * is cancelled after its first item.
*
Scheduler:
*
{@code timeout} does not operate by default on a particular {@link Scheduler}.
@@ -4736,30 +5990,31 @@ public final Maybe timeout(@NonNull Publisher timeoutIndicator) { * @param timeoutIndicator the {@code MaybeSource} that indicates the timeout by signaling {@code onSuccess} * or {@code onComplete} * @param fallback the {@code MaybeSource} that is subscribed to if the current {@code Maybe} times out - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code timeoutIndicator} or {@code fallback} is {@code null} */ @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe timeout(@NonNull Publisher timeoutIndicator, @NonNull MaybeSource fallback) { + public final <@NonNull U> Maybe timeout(@NonNull Publisher timeoutIndicator, @NonNull MaybeSource fallback) { Objects.requireNonNull(timeoutIndicator, "timeoutIndicator is null"); Objects.requireNonNull(fallback, "fallback is null"); return RxJavaPlugins.onAssembly(new MaybeTimeoutPublisher<>(this, timeoutIndicator, fallback)); } /** - * Returns a Maybe which makes sure when a MaybeObserver disposes the Disposable, - * that call is propagated up on the specified scheduler. + * Returns a {@code Maybe} which makes sure when a {@link MaybeObserver} disposes the {@link Disposable}, + * that call is propagated up on the specified {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
{@code unsubscribeOn} calls dispose() of the upstream on the {@link Scheduler} you specify.
+ *
{@code unsubscribeOn} calls {@code dispose()} of the upstream on the {@code Scheduler} you specify.
*
* @param scheduler the target scheduler where to execute the disposal - * @return the new Maybe instance - * @throws NullPointerException if scheduler is null + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code scheduler} is {@code null} */ @CheckReturnValue @NonNull @@ -4770,12 +6025,12 @@ public final Maybe unsubscribeOn(@NonNull Scheduler scheduler) { } /** - * Waits until this and the other MaybeSource signal a success value then applies the given BiFunction - * to those values and emits the BiFunction's resulting value to downstream. + * Waits until this and the other {@link MaybeSource} signal a success value then applies the given {@link BiFunction} + * to those values and emits the {@code BiFunction}'s resulting value to downstream. * * * - *

If either this or the other MaybeSource is empty or signals an error, the resulting Maybe will + *

If either this or the other {@code MaybeSource} is empty or signals an error, the resulting {@code Maybe} will * terminate immediately and dispose the other source. * *

@@ -4784,21 +6039,22 @@ public final Maybe unsubscribeOn(@NonNull Scheduler scheduler) { *
* * @param - * the type of items emitted by the {@code other} MaybeSource + * the type of items emitted by the {@code other} {@code MaybeSource} * @param - * the type of items emitted by the resulting Maybe + * the type of items emitted by the resulting {@code Maybe} * @param other - * the other MaybeSource + * the other {@code MaybeSource} * @param zipper - * a function that combines the pairs of items from the two MaybeSources to generate the items to - * be emitted by the resulting Maybe - * @return the new Maybe instance + * a function that combines the pairs of items from the two {@code MaybeSource}s to generate the items to + * be emitted by the resulting {@code Maybe} + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code other} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe zipWith(@NonNull MaybeSource other, @NonNull BiFunction zipper) { + public final <@NonNull U, @NonNull R> Maybe zipWith(@NonNull MaybeSource other, @NonNull BiFunction zipper) { Objects.requireNonNull(other, "other is null"); return zip(this, other, zipper); } @@ -4808,13 +6064,13 @@ public final Maybe zipWith(@NonNull MaybeSource other, @N // ------------------------------------------------------------------ /** - * Creates a TestObserver and subscribes - * it to this Maybe. + * Creates a {@link TestObserver} and subscribes + * it to this {@code Maybe}. *
*
Scheduler:
*
{@code test} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new TestObserver instance + * @return the new {@code TestObserver} instance */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -4826,14 +6082,14 @@ public final TestObserver test() { } /** - * Creates a TestObserver optionally in cancelled state, then subscribes it to this Maybe. + * Creates a {@link TestObserver} optionally in cancelled state, then subscribes it to this {@code Maybe}. *
*
Scheduler:
*
{@code test} does not operate by default on a particular {@link Scheduler}.
*
- * @param dispose if true, the TestObserver will be dispose before subscribing to this - * Maybe. - * @return the new TestObserver instance + * @param dispose if {@code true}, the {@code TestObserver} will be disposed before subscribing to this + * {@code Maybe}. + * @return the new {@code TestObserver} instance */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -4871,7 +6127,8 @@ public final TestObserver test(boolean dispose) { *
* @param the element type of the optional value * @param optional the optional value to convert into a {@code Maybe} - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code optional} is {@code null} * @since 3.0.0 * @see #just(Object) * @see #empty() @@ -4879,7 +6136,7 @@ public final TestObserver test(boolean dispose) { @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Maybe<@NonNull T> fromOptional(@NonNull Optional optional) { + public static <@NonNull T> Maybe<@NonNull T> fromOptional(@NonNull Optional optional) { Objects.requireNonNull(optional, "optional is null"); return optional.map(Maybe::just).orElseGet(Maybe::empty); } @@ -4890,7 +6147,7 @@ public final TestObserver test(boolean dispose) { * *

* Note that the operator takes an already instantiated, running or terminated {@code CompletionStage}. - * If the optional is to be created per consumer upon subscription, use {@link #defer(Supplier)} + * If the {@code CompletionStage} is to be created per consumer upon subscription, use {@link #defer(Supplier)} * around {@code fromCompletionStage}: *


      * Maybe.defer(() -> Maybe.fromCompletionStage(createCompletionStage()));
@@ -4904,15 +6161,16 @@ public final TestObserver test(boolean dispose) {
      *  
Scheduler:
*
{@code fromCompletionStage} does not operate by default on a particular {@link Scheduler}.
*
- * @param the element type of the CompletionStage - * @param stage the CompletionStage to convert to Maybe and signal its terminal value or error - * @return the new Maybe instance + * @param the element type of the {@code CompletionStage} + * @param stage the {@code CompletionStage} to convert to {@code Maybe} and signal its terminal value or error + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code stage} is {@code null} * @since 3.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Maybe<@NonNull T> fromCompletionStage(@NonNull CompletionStage stage) { + public static <@NonNull T> Maybe<@NonNull T> fromCompletionStage(@NonNull CompletionStage stage) { Objects.requireNonNull(stage, "stage is null"); return RxJavaPlugins.onAssembly(new MaybeFromCompletionStage<>(stage)); } @@ -4926,10 +6184,11 @@ public final TestObserver test(boolean dispose) { *
Scheduler:
*
{@code mapOptional} does not operate by default on a particular {@link Scheduler}.
*
- * @param the non-null output type + * @param the non-{@code null} output type * @param mapper the function that receives the upstream success item and should return a non-empty {@code Optional} * to emit as the success output or an empty {@code Optional} to complete the {@code Maybe} - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @since 3.0.0 * @see #map(Function) * @see #filter(Predicate) @@ -4964,7 +6223,7 @@ public final TestObserver test(boolean dispose) { *
Scheduler:
*
{@code toCompletionStage} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new CompletionStage instance + * @return the new {@code CompletionStage} instance * @since 3.0.0 * @see #toCompletionStage(Object) */ @@ -4997,7 +6256,7 @@ public final CompletionStage toCompletionStage() { *
{@code toCompletionStage} does not operate by default on a particular {@link Scheduler}.
*
* @param defaultItem the item to signal if the upstream is empty - * @return the new CompletionStage instance + * @return the new {@code CompletionStage} instance * @since 3.0.0 */ @CheckReturnValue @@ -5011,9 +6270,9 @@ public final CompletionStage toCompletionStage(@Nullable T defaultItem) { * Maps the upstream succecss value into a Java {@link Stream} and emits its * items to the downstream consumer as a {@link Flowable}. *

- * + * *

- * The operator closes the {@code Stream} upon cancellation and when it terminates. Exceptions raised when + * The operator closes the {@code Stream} upon cancellation and when it terminates. The exceptions raised when * closing a {@code Stream} are routed to the global error handler ({@link RxJavaPlugins#onError(Throwable)}. * If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #flattenAsFlowable(Function)}: *


@@ -5037,7 +6296,8 @@ public final CompletionStage toCompletionStage(@Nullable T defaultItem) {
      * @param  the element type of the {@code Stream} and the output {@code Flowable}
      * @param mapper the function that receives the upstream success item and should
      * return a {@code Stream} of values to emit.
-     * @return the new Flowable instance
+     * @return the new {@code Flowable} instance
+     * @throws NullPointerException if {@code mapper} is {@code null}
      * @since 3.0.0
      * @see #flattenAsFlowable(Function)
      * @see #flattenStreamAsObservable(Function)
@@ -5046,7 +6306,7 @@ public final CompletionStage toCompletionStage(@Nullable T defaultItem) {
     @SchedulerSupport(SchedulerSupport.NONE)
     @BackpressureSupport(BackpressureKind.FULL)
     @NonNull
-    public final  Flowable flattenStreamAsFlowable(@NonNull Function> mapper) {
+    public final <@NonNull R> Flowable flattenStreamAsFlowable(@NonNull Function> mapper) {
         Objects.requireNonNull(mapper, "mapper is null");
         return RxJavaPlugins.onAssembly(new MaybeFlattenStreamAsFlowable<>(this, mapper));
     }
@@ -5054,9 +6314,9 @@ public final  Flowable flattenStreamAsFlowable(@NonNull Function
+     * 
      * 

- * The operator closes the {@code Stream} upon cancellation and when it terminates. Exceptions raised when + * The operator closes the {@code Stream} upon cancellation and when it terminates. The exceptions raised when * closing a {@code Stream} are routed to the global error handler ({@link RxJavaPlugins#onError(Throwable)}. * If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #flattenAsObservable(Function)}: *


@@ -5077,7 +6337,8 @@ public final  Flowable flattenStreamAsFlowable(@NonNull Function the element type of the {@code Stream} and the output {@code Observable}
      * @param mapper the function that receives the upstream success item and should
      * return a {@code Stream} of values to emit.
-     * @return the new Observable instance
+     * @return the new {@code Observable} instance
+     * @throws NullPointerException if {@code mapper} is {@code null}
      * @since 3.0.0
      * @see #flattenAsObservable(Function)
      * @see #flattenStreamAsFlowable(Function)
@@ -5085,7 +6346,7 @@ public final  Flowable flattenStreamAsFlowable(@NonNull Function Observable flattenStreamAsObservable(@NonNull Function> mapper) {
+    public final <@NonNull R> Observable flattenStreamAsObservable(@NonNull Function> mapper) {
         Objects.requireNonNull(mapper, "mapper is null");
         return RxJavaPlugins.onAssembly(new MaybeFlattenStreamAsObservable<>(this, mapper));
     }
diff --git a/src/main/java/io/reactivex/rxjava3/core/MaybeConverter.java b/src/main/java/io/reactivex/rxjava3/core/MaybeConverter.java
index eefe8c0973c..6ef529de7ef 100644
--- a/src/main/java/io/reactivex/rxjava3/core/MaybeConverter.java
+++ b/src/main/java/io/reactivex/rxjava3/core/MaybeConverter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -24,7 +24,7 @@
  * @since 2.2
  */
 @FunctionalInterface
-public interface MaybeConverter {
+public interface MaybeConverter<@NonNull T, @NonNull R> {
     /**
      * Applies a function to the upstream {@link Maybe} and returns a converted value of type {@code R}.
      *
diff --git a/src/main/java/io/reactivex/rxjava3/core/MaybeEmitter.java b/src/main/java/io/reactivex/rxjava3/core/MaybeEmitter.java
index 7757e4b72ad..57d7f5a2191 100644
--- a/src/main/java/io/reactivex/rxjava3/core/MaybeEmitter.java
+++ b/src/main/java/io/reactivex/rxjava3/core/MaybeEmitter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -15,7 +15,7 @@
 
 import io.reactivex.rxjava3.annotations.*;
 import io.reactivex.rxjava3.disposables.Disposable;
-import io.reactivex.rxjava3.functions.Cancellable;
+import io.reactivex.rxjava3.functions.*;
 
 /**
  * Abstraction over an RxJava {@link MaybeObserver} that allows associating
@@ -47,7 +47,7 @@
  *
  * @param  the value type to emit
  */
-public interface MaybeEmitter {
+public interface MaybeEmitter<@NonNull T> {
 
     /**
      * Signal a success value.
diff --git a/src/main/java/io/reactivex/rxjava3/core/MaybeObserver.java b/src/main/java/io/reactivex/rxjava3/core/MaybeObserver.java
index 52bee5923ad..f6567dc94e9 100644
--- a/src/main/java/io/reactivex/rxjava3/core/MaybeObserver.java
+++ b/src/main/java/io/reactivex/rxjava3/core/MaybeObserver.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -53,7 +53,7 @@
  *          the type of item the MaybeObserver expects to observe
  * @since 2.0
  */
-public interface MaybeObserver {
+public interface MaybeObserver<@NonNull T> {
 
     /**
      * Provides the {@link MaybeObserver} with the means of cancelling (disposing) the
diff --git a/src/main/java/io/reactivex/rxjava3/core/MaybeOnSubscribe.java b/src/main/java/io/reactivex/rxjava3/core/MaybeOnSubscribe.java
index 350d17af5db..67994d3d407 100644
--- a/src/main/java/io/reactivex/rxjava3/core/MaybeOnSubscribe.java
+++ b/src/main/java/io/reactivex/rxjava3/core/MaybeOnSubscribe.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -10,19 +10,20 @@
  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
  * the License for the specific language governing permissions and limitations under the License.
  */
+
 package io.reactivex.rxjava3.core;
 
 import io.reactivex.rxjava3.annotations.NonNull;
 
 /**
  * A functional interface that has a {@code subscribe()} method that receives
- * an instance of a {@link MaybeEmitter} instance that allows pushing
+ * a {@link MaybeEmitter} instance that allows pushing
  * an event in a cancellation-safe manner.
  *
  * @param  the value type pushed
  */
 @FunctionalInterface
-public interface MaybeOnSubscribe {
+public interface MaybeOnSubscribe<@NonNull T> {
 
     /**
      * Called for each {@link MaybeObserver} that subscribes.
diff --git a/src/main/java/io/reactivex/rxjava3/core/MaybeOperator.java b/src/main/java/io/reactivex/rxjava3/core/MaybeOperator.java
index 30da3286b6e..7cea758dd92 100644
--- a/src/main/java/io/reactivex/rxjava3/core/MaybeOperator.java
+++ b/src/main/java/io/reactivex/rxjava3/core/MaybeOperator.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -10,6 +10,7 @@
  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
  * the License for the specific language governing permissions and limitations under the License.
  */
+
 package io.reactivex.rxjava3.core;
 
 import io.reactivex.rxjava3.annotations.NonNull;
@@ -21,7 +22,7 @@
  * @param  the value type of the upstream
  */
 @FunctionalInterface
-public interface MaybeOperator {
+public interface MaybeOperator<@NonNull Downstream, @NonNull Upstream> {
     /**
      * Applies a function to the child {@link MaybeObserver} and returns a new parent {@code MaybeObserver}.
      * @param observer the child {@code MaybeObserver} instance
diff --git a/src/main/java/io/reactivex/rxjava3/core/MaybeSource.java b/src/main/java/io/reactivex/rxjava3/core/MaybeSource.java
index f066e5d32ea..a15ea2c89d6 100644
--- a/src/main/java/io/reactivex/rxjava3/core/MaybeSource.java
+++ b/src/main/java/io/reactivex/rxjava3/core/MaybeSource.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -10,6 +10,7 @@
  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
  * the License for the specific language governing permissions and limitations under the License.
  */
+
 package io.reactivex.rxjava3.core;
 
 import io.reactivex.rxjava3.annotations.NonNull;
@@ -25,7 +26,7 @@
  * @since 2.0
  */
 @FunctionalInterface
-public interface MaybeSource {
+public interface MaybeSource<@NonNull T> {
 
     /**
      * Subscribes the given {@link MaybeObserver} to this {@link MaybeSource} instance.
diff --git a/src/main/java/io/reactivex/rxjava3/core/MaybeTransformer.java b/src/main/java/io/reactivex/rxjava3/core/MaybeTransformer.java
index aebcb8353f9..770497fe3c9 100644
--- a/src/main/java/io/reactivex/rxjava3/core/MaybeTransformer.java
+++ b/src/main/java/io/reactivex/rxjava3/core/MaybeTransformer.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -22,7 +22,7 @@
  * @param  the downstream value type
  */
 @FunctionalInterface
-public interface MaybeTransformer {
+public interface MaybeTransformer<@NonNull Upstream, @NonNull Downstream> {
     /**
      * Applies a function to the upstream {@link Maybe} and returns a {@link MaybeSource} with
      * optionally different element type.
diff --git a/src/main/java/io/reactivex/rxjava3/core/Notification.java b/src/main/java/io/reactivex/rxjava3/core/Notification.java
index 086ffafc8e1..7f5896209f8 100644
--- a/src/main/java/io/reactivex/rxjava3/core/Notification.java
+++ b/src/main/java/io/reactivex/rxjava3/core/Notification.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -26,7 +26,9 @@ public final class Notification {
 
     final Object value;
 
-    /** Not meant to be implemented externally. */
+    /** Not meant to be implemented externally.
+     * @param value the value to carry around in the notification, not {@code null}
+     */
     private Notification(@Nullable Object value) {
         this.value = value;
     }
diff --git a/src/main/java/io/reactivex/rxjava3/core/Observable.java b/src/main/java/io/reactivex/rxjava3/core/Observable.java
index 7a8d8080720..fcf809cdf6b 100644
--- a/src/main/java/io/reactivex/rxjava3/core/Observable.java
+++ b/src/main/java/io/reactivex/rxjava3/core/Observable.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -20,37 +20,39 @@
 import org.reactivestreams.Publisher;
 
 import io.reactivex.rxjava3.annotations.*;
-import io.reactivex.rxjava3.disposables.Disposable;
-import io.reactivex.rxjava3.exceptions.Exceptions;
+import io.reactivex.rxjava3.disposables.*;
+import io.reactivex.rxjava3.exceptions.*;
 import io.reactivex.rxjava3.functions.*;
 import io.reactivex.rxjava3.internal.functions.*;
-import io.reactivex.rxjava3.internal.fuseable.ScalarSupplier;
 import io.reactivex.rxjava3.internal.jdk8.*;
 import io.reactivex.rxjava3.internal.observers.*;
 import io.reactivex.rxjava3.internal.operators.flowable.*;
+import io.reactivex.rxjava3.internal.operators.maybe.MaybeToObservable;
 import io.reactivex.rxjava3.internal.operators.mixed.*;
 import io.reactivex.rxjava3.internal.operators.observable.*;
+import io.reactivex.rxjava3.internal.operators.single.SingleToObservable;
 import io.reactivex.rxjava3.internal.util.*;
 import io.reactivex.rxjava3.observables.*;
 import io.reactivex.rxjava3.observers.*;
+import io.reactivex.rxjava3.operators.ScalarSupplier;
 import io.reactivex.rxjava3.plugins.RxJavaPlugins;
 import io.reactivex.rxjava3.schedulers.*;
 
 /**
- * The Observable class is the non-backpressured, optionally multi-valued base reactive class that
+ * The {@code Observable} class is the non-backpressured, optionally multi-valued base reactive class that
  * offers factory methods, intermediate operators and the ability to consume synchronous
  * and/or asynchronous reactive dataflows.
  * 

- * Many operators in the class accept {@code ObservableSource}(s), the base reactive interface + * Many operators in the class accept {@link ObservableSource}(s), the base reactive interface * for such non-backpressured flows, which {@code Observable} itself implements as well. *

- * The Observable's operators, by default, run with a buffer size of 128 elements (see {@link Flowable#bufferSize()}), + * The {@code Observable}'s operators, by default, run with a buffer size of 128 elements (see {@link Flowable#bufferSize()}), * that can be overridden globally via the system parameter {@code rx3.buffer-size}. Most operators, however, have * overloads that allow setting their internal buffer size explicitly. *

* The documentation for this class makes use of marble diagrams. The following legend explains these diagrams: *

- * + * *

* The design of this class was derived from the * Reactive-Streams design and specification @@ -67,7 +69,7 @@ * {@code Observer.onSubscribe}. *

* Unlike the {@code Observable} of version 1.x, {@link #subscribe(Observer)} does not allow external disposal - * of a subscription and the {@code Observer} instance is expected to expose such capability. + * of a subscription and the {@link Observer} instance is expected to expose such capability. *

Example: *


  * Disposable d = Observable.just("Hello world!")
@@ -93,54 +95,70 @@
  * 
* * @param - * the type of the items emitted by the Observable + * the type of the items emitted by the {@code Observable} * @see Flowable * @see io.reactivex.rxjava3.observers.DisposableObserver */ -public abstract class Observable implements ObservableSource { +public abstract class Observable<@NonNull T> implements ObservableSource { /** - * Mirrors the one ObservableSource in an Iterable of several ObservableSources that first either emits an item or sends + * Mirrors the one {@link ObservableSource} in an {@link Iterable} of several {@code ObservableSource}s that first either emits an item or sends * a termination notification. *

- * + * + *

+ * When one of the {@code ObservableSource}s signal an item or terminates first, all subscriptions to the other + * {@code ObservableSource}s are disposed. *

*
Scheduler:
*
{@code amb} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
+ * If any of the losing {@code ObservableSource}s signals an error, the error is routed to the global + * error handler via {@link RxJavaPlugins#onError(Throwable)}. + *
*
* * @param the common element type * @param sources - * an Iterable of ObservableSource sources competing to react first. A subscription to each source will - * occur in the same order as in the Iterable. - * @return an Observable that emits the same sequence as whichever of the source ObservableSources first - * emitted an item or sent a termination notification + * an {@code Iterable} of {@code ObservableSource} sources competing to react first. A subscription to each source will + * occur in the same order as in the {@code Iterable}. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Amb */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable amb(@NonNull Iterable> sources) { + public static <@NonNull T> Observable amb(@NonNull Iterable<@NonNull ? extends ObservableSource> sources) { Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new ObservableAmb<>(null, sources)); } /** - * Mirrors the one ObservableSource in an array of several ObservableSources that first either emits an item or sends + * Mirrors the one {@link ObservableSource} in an array of several {@code ObservableSource}s that first either emits an item or sends * a termination notification. *

- * + * + *

+ * When one of the {@code ObservableSource}s signal an item or terminates first, all subscriptions to the other + * {@code ObservableSource}s are disposed. *

*
Scheduler:
*
{@code ambArray} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
+ * If any of the losing {@code ObservableSource}s signals an error, the error is routed to the global + * error handler via {@link RxJavaPlugins#onError(Throwable)}. + *
*
* * @param the common element type * @param sources - * an array of ObservableSource sources competing to react first. A subscription to each source will + * an array of {@code ObservableSource} sources competing to react first. A subscription to each source will * occur in the same order as in the array. - * @return an Observable that emits the same sequence as whichever of the source ObservableSources first - * emitted an item or sent a termination notification + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Amb */ @SuppressWarnings("unchecked") @@ -148,7 +166,7 @@ public static Observable amb(@NonNull Iterable Observable ambArray(@NonNull ObservableSource... sources) { + public static <@NonNull T> Observable ambArray(@NonNull ObservableSource... sources) { Objects.requireNonNull(sources, "sources is null"); int len = sources.length; if (len == 0) { @@ -173,23 +191,23 @@ public static int bufferSize() { } /** - * Combines a collection of source ObservableSources by emitting an item that aggregates the latest values of each of - * the source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines a collection of source {@link ObservableSource}s by emitting an item that aggregates the latest values of each of + * the returned {@code ObservableSource}s each time an item is received from any of the returned {@code ObservableSource}s, where this * aggregation is defined by a specified function. *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * If the provided iterable of ObservableSources is empty, the resulting sequence completes immediately without emitting + * If the provided iterable of {@code ObservableSource}s is empty, the resulting sequence completes immediately without emitting * any items and without any calls to the combiner function. * *

- * + * *

*
Scheduler:
*
{@code combineLatest} does not operate by default on a particular {@link Scheduler}.
@@ -200,40 +218,40 @@ public static int bufferSize() { * @param * the result type * @param sources - * the collection of source ObservableSources + * the collection of source {@code ObservableSource}s * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the aggregation function used to combine the items emitted by the returned {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable combineLatest( - @NonNull Iterable> sources, + public static <@NonNull T, @NonNull R> Observable combineLatest( + @NonNull Iterable<@NonNull ? extends ObservableSource> sources, @NonNull Function combiner) { return combineLatest(sources, combiner, bufferSize()); } /** - * Combines a collection of source ObservableSources by emitting an item that aggregates the latest values of each of - * the source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines an {@link Iterable} of source {@link ObservableSource}s by emitting an item that aggregates the latest values of each of + * the returned {@code ObservableSource}s each time an item is received from any of the returned {@code ObservableSource}s, where this * aggregation is defined by a specified function. *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * If the provided iterable of ObservableSources is empty, the resulting sequence completes immediately without emitting + * If the provided {@code Iterable} of {@code ObservableSource}s is empty, the resulting sequence completes immediately without emitting * any items and without any calls to the combiner function. * *

- * + * *

*
Scheduler:
*
{@code combineLatest} does not operate by default on a particular {@link Scheduler}.
@@ -244,20 +262,21 @@ public static Observable combineLatest( * @param * the result type * @param sources - * the collection of source ObservableSources + * the collection of source {@code ObservableSource}s * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources + * the aggregation function used to combine the items emitted by the returned {@code ObservableSource}s * @param bufferSize - * the internal buffer size and prefetch amount applied to every source Observable - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the expected number of row combination items to be buffered internally + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} or {@code combiner} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: CombineLatest */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable combineLatest( - @NonNull Iterable> sources, + public static <@NonNull T, @NonNull R> Observable combineLatest( + @NonNull Iterable<@NonNull ? extends ObservableSource> sources, @NonNull Function combiner, int bufferSize) { Objects.requireNonNull(sources, "sources is null"); Objects.requireNonNull(combiner, "combiner is null"); @@ -269,23 +288,23 @@ public static Observable combineLatest( } /** - * Combines a collection of source ObservableSources by emitting an item that aggregates the latest values of each of - * the source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines an array of source {@link ObservableSource}s by emitting an item that aggregates the latest values of each of + * the {@code ObservableSource}s each time an item is received from any of the returned {@code ObservableSource}s, where this * aggregation is defined by a specified function. *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * If the provided array of ObservableSources is empty, the resulting sequence completes immediately without emitting + * If the provided array of {@code ObservableSource}s is empty, the resulting sequence completes immediately without emitting * any items and without any calls to the combiner function. * *

- * + * *

*
Scheduler:
*
{@code combineLatestArray} does not operate by default on a particular {@link Scheduler}.
@@ -296,40 +315,40 @@ public static Observable combineLatest( * @param * the result type * @param sources - * the collection of source ObservableSources + * the collection of source {@code ObservableSource}s * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable combineLatestArray( + public static <@NonNull T, @NonNull R> Observable combineLatestArray( @NonNull ObservableSource[] sources, @NonNull Function combiner) { return combineLatestArray(sources, combiner, bufferSize()); } /** - * Combines a collection of source ObservableSources by emitting an item that aggregates the latest values of each of - * the source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines an array of source {@link ObservableSource}s by emitting an item that aggregates the latest values of each of + * the {@code ObservableSource}s each time an item is received from any of the {@code ObservableSource}s, where this * aggregation is defined by a specified function. *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * If the provided array of ObservableSources is empty, the resulting sequence completes immediately without emitting + * If the provided array of {@code ObservableSource}s is empty, the resulting sequence completes immediately without emitting * any items and without any calls to the combiner function. * *

- * + * *

*
Scheduler:
*
{@code combineLatestArray} does not operate by default on a particular {@link Scheduler}.
@@ -340,19 +359,20 @@ public static Observable combineLatestArray( * @param * the result type * @param sources - * the collection of source ObservableSources + * the collection of source {@code ObservableSource}s * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s * @param bufferSize - * the internal buffer size and prefetch amount applied to every source Observable - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the expected number of row combination items to be buffered internally + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} or {@code combiner} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: CombineLatest */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable combineLatestArray( + public static <@NonNull T, @NonNull R> Observable combineLatestArray( @NonNull ObservableSource[] sources, @NonNull Function combiner, int bufferSize) { Objects.requireNonNull(sources, "sources is null"); @@ -368,15 +388,15 @@ public static Observable combineLatestArray( } /** - * Combines two source ObservableSources by emitting an item that aggregates the latest values of each of the - * source ObservableSources each time an item is received from either of the source ObservableSources, where this + * Combines two source {@link ObservableSource}s by emitting an item that aggregates the latest values of each of the + * {@code ObservableSource}s each time an item is received from either of the {@code ObservableSource}s, where this * aggregation is defined by a specified function. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Scheduler:
*
{@code combineLatest} does not operate by default on a particular {@link Scheduler}.
@@ -386,20 +406,20 @@ public static Observable combineLatestArray( * @param the element type of the second source * @param the combined output type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * the second source ObservableSource + * the second source {@code ObservableSource} * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull R> Observable combineLatest( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull BiFunction combiner) { Objects.requireNonNull(source1, "source1 is null"); @@ -409,15 +429,15 @@ public static Observable combineLatest( } /** - * Combines three source ObservableSources by emitting an item that aggregates the latest values of each of the - * source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines three source {@link ObservableSource}s by emitting an item that aggregates the latest values of each of the + * {@code ObservableSource}s each time an item is received from any of the {@code ObservableSource}s, where this * aggregation is defined by a specified function. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Scheduler:
*
{@code combineLatest} does not operate by default on a particular {@link Scheduler}.
@@ -428,22 +448,22 @@ public static Observable combineLatest( * @param the element type of the third source * @param the combined output type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * the second source ObservableSource + * the second source {@code ObservableSource} * @param source3 - * the third source ObservableSource + * the third source {@code ObservableSource} * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull R> Observable combineLatest( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull Function3 combiner) { @@ -455,15 +475,15 @@ public static Observable combineLatest( } /** - * Combines four source ObservableSources by emitting an item that aggregates the latest values of each of the - * source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines four source {@link ObservableSource}s by emitting an item that aggregates the latest values of each of the + * {@code ObservableSource}s each time an item is received from any of the {@code ObservableSource}s, where this * aggregation is defined by a specified function. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Scheduler:
*
{@code combineLatest} does not operate by default on a particular {@link Scheduler}.
@@ -475,24 +495,25 @@ public static Observable combineLatest( * @param the element type of the fourth source * @param the combined output type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * the second source ObservableSource + * the second source {@code ObservableSource} * @param source3 - * the third source ObservableSource + * the third source {@code ObservableSource} * @param source4 - * the fourth source ObservableSource + * the fourth source {@code ObservableSource} * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull R> Observable combineLatest( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4, @NonNull Function4 combiner) { @@ -505,15 +526,15 @@ public static Observable combineLatest( } /** - * Combines five source ObservableSources by emitting an item that aggregates the latest values of each of the - * source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines five source {@link ObservableSource}s by emitting an item that aggregates the latest values of each of the + * {@code ObservableSource}s each time an item is received from any of the {@code ObservableSource}s, where this * aggregation is defined by a specified function. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Scheduler:
*
{@code combineLatest} does not operate by default on a particular {@link Scheduler}.
@@ -526,26 +547,27 @@ public static Observable combineLatest( * @param the element type of the fifth source * @param the combined output type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * the second source ObservableSource + * the second source {@code ObservableSource} * @param source3 - * the third source ObservableSource + * the third source {@code ObservableSource} * @param source4 - * the fourth source ObservableSource + * the fourth source {@code ObservableSource} * @param source5 - * the fifth source ObservableSource + * the fifth source {@code ObservableSource} * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull R> Observable combineLatest( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4, @NonNull ObservableSource source5, @@ -560,15 +582,15 @@ public static Observable combineLatest( } /** - * Combines six source ObservableSources by emitting an item that aggregates the latest values of each of the - * source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines six source {@link ObservableSource}s by emitting an item that aggregates the latest values of each of the + * {@code ObservableSource}s each time an item is received from any of the {@code ObservableSource}s, where this * aggregation is defined by a specified function. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Scheduler:
*
{@code combineLatest} does not operate by default on a particular {@link Scheduler}.
@@ -582,28 +604,29 @@ public static Observable combineLatest( * @param the element type of the sixth source * @param the combined output type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * the second source ObservableSource + * the second source {@code ObservableSource} * @param source3 - * the third source ObservableSource + * the third source {@code ObservableSource} * @param source4 - * the fourth source ObservableSource + * the fourth source {@code ObservableSource} * @param source5 - * the fifth source ObservableSource + * the fifth source {@code ObservableSource} * @param source6 - * the sixth source ObservableSource + * the sixth source {@code ObservableSource} * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull R> Observable combineLatest( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4, @NonNull ObservableSource source5, @NonNull ObservableSource source6, @@ -619,15 +642,15 @@ public static Observable combineLatest( } /** - * Combines seven source ObservableSources by emitting an item that aggregates the latest values of each of the - * source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines seven source {@link ObservableSource}s by emitting an item that aggregates the latest values of each of the + * {@code ObservableSource}s each time an item is received from any of the {@code ObservableSource}s, where this * aggregation is defined by a specified function. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Scheduler:
*
{@code combineLatest} does not operate by default on a particular {@link Scheduler}.
@@ -642,30 +665,32 @@ public static Observable combineLatest( * @param the element type of the seventh source * @param the combined output type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * the second source ObservableSource + * the second source {@code ObservableSource} * @param source3 - * the third source ObservableSource + * the third source {@code ObservableSource} * @param source4 - * the fourth source ObservableSource + * the fourth source {@code ObservableSource} * @param source5 - * the fifth source ObservableSource + * the fifth source {@code ObservableSource} * @param source6 - * the sixth source ObservableSource + * the sixth source {@code ObservableSource} * @param source7 - * the seventh source ObservableSource + * the seventh source {@code ObservableSource} * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull R> Observable combineLatest( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4, @NonNull ObservableSource source5, @NonNull ObservableSource source6, @@ -683,15 +708,15 @@ public static Observable combineLatest( } /** - * Combines eight source ObservableSources by emitting an item that aggregates the latest values of each of the - * source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines eight source {@link ObservableSource}s by emitting an item that aggregates the latest values of each of the + * {@code ObservableSource}s each time an item is received from any of the {@code ObservableSource}s, where this * aggregation is defined by a specified function. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Scheduler:
*
{@code combineLatest} does not operate by default on a particular {@link Scheduler}.
@@ -707,32 +732,34 @@ public static Observable combineLatest( * @param the element type of the eighth source * @param the combined output type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * the second source ObservableSource + * the second source {@code ObservableSource} * @param source3 - * the third source ObservableSource + * the third source {@code ObservableSource} * @param source4 - * the fourth source ObservableSource + * the fourth source {@code ObservableSource} * @param source5 - * the fifth source ObservableSource + * the fifth source {@code ObservableSource} * @param source6 - * the sixth source ObservableSource + * the sixth source {@code ObservableSource} * @param source7 - * the seventh source ObservableSource + * the seventh source {@code ObservableSource} * @param source8 - * the eighth source ObservableSource + * the eighth source {@code ObservableSource} * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7}, {@code source8} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull R> Observable combineLatest( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4, @NonNull ObservableSource source5, @NonNull ObservableSource source6, @@ -751,15 +778,15 @@ public static Observable combineLatest( } /** - * Combines nine source ObservableSources by emitting an item that aggregates the latest values of each of the - * source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines nine source {@link ObservableSource}s by emitting an item that aggregates the latest values of each of the + * {@code ObservableSource}s each time an item is received from any of the {@code ObservableSource}s, where this * aggregation is defined by a specified function. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * + * *

*
Scheduler:
*
{@code combineLatest} does not operate by default on a particular {@link Scheduler}.
@@ -776,34 +803,36 @@ public static Observable combineLatest( * @param the element type of the ninth source * @param the combined output type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * the second source ObservableSource + * the second source {@code ObservableSource} * @param source3 - * the third source ObservableSource + * the third source {@code ObservableSource} * @param source4 - * the fourth source ObservableSource + * the fourth source {@code ObservableSource} * @param source5 - * the fifth source ObservableSource + * the fifth source {@code ObservableSource} * @param source6 - * the sixth source ObservableSource + * the sixth source {@code ObservableSource} * @param source7 - * the seventh source ObservableSource + * the seventh source {@code ObservableSource} * @param source8 - * the eighth source ObservableSource + * the eighth source {@code ObservableSource} * @param source9 - * the ninth source ObservableSource + * the ninth source {@code ObservableSource} * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7}, {@code source8}, {@code source9} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @SuppressWarnings("unchecked") @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable combineLatest( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull T9, @NonNull R> Observable combineLatest( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4, @NonNull ObservableSource source5, @NonNull ObservableSource source6, @@ -824,26 +853,26 @@ public static Observable combineLates } /** - * Combines a collection of source ObservableSources by emitting an item that aggregates the latest values of each of - * the source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines an array of {@link ObservableSource}s by emitting an item that aggregates the latest values of each of + * the {@code ObservableSource}s each time an item is received from any of the {@code ObservableSource}s, where this * aggregation is defined by a specified function. *

- * + * *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * If the provided array of ObservableSources is empty, the resulting sequence completes immediately without emitting + * If the provided array of {@code ObservableSource}s is empty, the resulting sequence completes immediately without emitting * any items and without any calls to the combiner function. * *

*
Scheduler:
- *
{@code combineLatestDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
{@code combineLatestArrayDelayError} does not operate by default on a particular {@link Scheduler}.
*
* * @param @@ -851,44 +880,44 @@ public static Observable combineLates * @param * the result type * @param sources - * the collection of source ObservableSources + * the collection of source {@code ObservableSource}s * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable combineLatestDelayError( + public static <@NonNull T, @NonNull R> Observable combineLatestArrayDelayError( @NonNull ObservableSource[] sources, @NonNull Function combiner) { - return combineLatestDelayError(sources, combiner, bufferSize()); + return combineLatestArrayDelayError(sources, combiner, bufferSize()); } /** - * Combines a collection of source ObservableSources by emitting an item that aggregates the latest values of each of - * the source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines an array of {@link ObservableSource}s by emitting an item that aggregates the latest values of each of + * the {@code ObservableSource}s each time an item is received from any of the {@code ObservableSource}s, where this * aggregation is defined by a specified function and delays any error from the sources until - * all source ObservableSources terminate. + * all source {@code ObservableSource}s terminate. *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * If the provided array of ObservableSources is empty, the resulting sequence completes immediately without emitting + * If the provided array of {@code ObservableSource}s is empty, the resulting sequence completes immediately without emitting * any items and without any calls to the combiner function. * *

- * + * *

*
Scheduler:
- *
{@code combineLatestDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
{@code combineLatestArrayDelayError} does not operate by default on a particular {@link Scheduler}.
*
* * @param @@ -896,22 +925,24 @@ public static Observable combineLatestDelayError( * @param * the result type * @param sources - * the collection of source ObservableSources + * the collection of source {@code ObservableSource}s * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s * @param bufferSize - * the internal buffer size and prefetch amount applied to every source Observable - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the expected number of row combination items to be buffered internally + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} or {@code combiner} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: CombineLatest */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable combineLatestDelayError(@NonNull ObservableSource[] sources, + public static <@NonNull T, @NonNull R> Observable combineLatestArrayDelayError(@NonNull ObservableSource[] sources, @NonNull Function combiner, int bufferSize) { - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + Objects.requireNonNull(sources, "sources is null"); Objects.requireNonNull(combiner, "combiner is null"); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); if (sources.length == 0) { return empty(); } @@ -921,24 +952,24 @@ public static Observable combineLatestDelayError(@NonNull ObservableSo } /** - * Combines a collection of source ObservableSources by emitting an item that aggregates the latest values of each of - * the source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines an {@link Iterable} of {@link ObservableSource}s by emitting an item that aggregates the latest values of each of + * the {@code ObservableSource}s each time an item is received from any of the {@code ObservableSource}s, where this * aggregation is defined by a specified function and delays any error from the sources until - * all source ObservableSources terminate. + * all source {@code ObservableSource}s terminate. *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * If the provided iterable of ObservableSources is empty, the resulting sequence completes immediately without emitting + * If the provided iterable of {@code ObservableSource}s is empty, the resulting sequence completes immediately without emitting * any items and without any calls to the combiner function. * *

- * + * *

*
Scheduler:
*
{@code combineLatestDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -949,40 +980,40 @@ public static Observable combineLatestDelayError(@NonNull ObservableSo * @param * the result type * @param sources - * the collection of source ObservableSources + * the {@code Iterable} of source {@code ObservableSource}s * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: CombineLatest */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable combineLatestDelayError(@NonNull Iterable> sources, + public static <@NonNull T, @NonNull R> Observable combineLatestDelayError(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, @NonNull Function combiner) { return combineLatestDelayError(sources, combiner, bufferSize()); } /** - * Combines a collection of source ObservableSources by emitting an item that aggregates the latest values of each of - * the source ObservableSources each time an item is received from any of the source ObservableSources, where this + * Combines an {@link Iterable} of {@link ObservableSource}s by emitting an item that aggregates the latest values of each of + * the {@code ObservableSource}s each time an item is received from any of the {@code ObservableSource}s, where this * aggregation is defined by a specified function and delays any error from the sources until - * all source ObservableSources terminate. + * all source {@code ObservableSource}s terminate. *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. *

* If any of the sources never produces an item but only terminates (normally or with an error), the * resulting sequence terminates immediately (normally or with all the errors accumulated till that point). * If that input source is also synchronous, other sources after it will not be subscribed to. *

- * If the provided iterable of ObservableSources is empty, the resulting sequence completes immediately without emitting + * If the provided iterable of {@code ObservableSource}s is empty, the resulting sequence completes immediately without emitting * any items and without any calls to the combiner function. * *

- * + * *

*
Scheduler:
*
{@code combineLatestDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -993,19 +1024,20 @@ public static Observable combineLatestDelayError(@NonNull Iterable * the result type * @param sources - * the collection of source ObservableSources + * the collection of source {@code ObservableSource}s * @param combiner - * the aggregation function used to combine the items emitted by the source ObservableSources + * the aggregation function used to combine the items emitted by the {@code ObservableSource}s * @param bufferSize - * the internal buffer size and prefetch amount applied to every source Observable - * @return an Observable that emits items that are the result of combining the items emitted by the source - * ObservableSources by means of the given aggregation function + * the expected number of row combination items to be buffered internally + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} or {@code combiner} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: CombineLatest */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable combineLatestDelayError(@NonNull Iterable> sources, + public static <@NonNull T, @NonNull R> Observable combineLatestDelayError(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, @NonNull Function combiner, int bufferSize) { Objects.requireNonNull(sources, "sources is null"); Objects.requireNonNull(combiner, "combiner is null"); @@ -1017,32 +1049,33 @@ public static Observable combineLatestDelayError(@NonNull Iterable - * + * *
*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
*
* @param the common value type of the sources - * @param sources the Iterable sequence of ObservableSources - * @return the new Observable instance + * @param sources the {@code Iterable} sequence of {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable concat(@NonNull Iterable> sources) { + public static <@NonNull T> Observable concat(@NonNull Iterable<@NonNull ? extends ObservableSource> sources) { Objects.requireNonNull(sources, "sources is null"); return fromIterable(sources).concatMapDelayError((Function)Functions.identity(), false, bufferSize()); } /** - * Returns an Observable that emits the items emitted by each of the ObservableSources emitted by the source - * ObservableSource, one after the other, without interleaving them. + * Returns an {@code Observable} that emits the items emitted by each of the {@link ObservableSource}s emitted by the + * {@code ObservableSource}, one after the other, without interleaving them. *

- * + * *

*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
@@ -1050,23 +1083,23 @@ public static Observable concat(@NonNull Iterable the common element base type * @param sources - * an ObservableSource that emits ObservableSources - * @return an Observable that emits items all of the items emitted by the ObservableSources emitted by - * {@code ObservableSources}, one after the other, without interleaving them + * an {@code ObservableSource} that emits {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Concat */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable concat(@NonNull ObservableSource> sources) { + public static <@NonNull T> Observable concat(@NonNull ObservableSource> sources) { return concat(sources, bufferSize()); } /** - * Returns an Observable that emits the items emitted by each of the ObservableSources emitted by the source - * ObservableSource, one after the other, without interleaving them. + * Returns an {@code Observable} that emits the items emitted by each of the {@link ObservableSource}s emitted by the outer + * {@code ObservableSource}, one after the other, without interleaving them. *

- * + * *

*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
@@ -1074,28 +1107,29 @@ public static Observable concat(@NonNull ObservableSource the common element base type * @param sources - * an ObservableSource that emits ObservableSources - * @param prefetch - * the number of ObservableSources to prefetch from the sources sequence. - * @return an Observable that emits items all of the items emitted by the ObservableSources emitted by - * {@code ObservableSources}, one after the other, without interleaving them + * an {@code ObservableSource} that emits {@code ObservableSource}s + * @param bufferSize + * the number of inner {@code ObservableSource}s expected to be buffered. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Concat */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable concat(@NonNull ObservableSource> sources, int prefetch) { + public static <@NonNull T> Observable concat(@NonNull ObservableSource> sources, int bufferSize) { Objects.requireNonNull(sources, "sources is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new ObservableConcatMap(sources, Functions.identity(), prefetch, ErrorMode.IMMEDIATE)); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + return RxJavaPlugins.onAssembly(new ObservableConcatMap(sources, Functions.identity(), bufferSize, ErrorMode.IMMEDIATE)); } /** - * Returns an Observable that emits the items emitted by two ObservableSources, one after the other, without + * Returns an {@code Observable} that emits the items emitted by two {@link ObservableSource}s, one after the other, without * interleaving them. *

- * + * *

*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
@@ -1103,27 +1137,27 @@ public static Observable concat(@NonNull ObservableSource the common element base type * @param source1 - * an ObservableSource to be concatenated + * an {@code ObservableSource} to be concatenated * @param source2 - * an ObservableSource to be concatenated - * @return an Observable that emits items emitted by the two source ObservableSources, one after the other, - * without interleaving them + * an {@code ObservableSource} to be concatenated + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @see ReactiveX operators documentation: Concat */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable concat(@NonNull ObservableSource source1, ObservableSource source2) { + public static <@NonNull T> Observable concat(@NonNull ObservableSource source1, ObservableSource source2) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); return concatArray(source1, source2); } /** - * Returns an Observable that emits the items emitted by three ObservableSources, one after the other, without + * Returns an {@code Observable} that emits the items emitted by three {@link ObservableSource}s, one after the other, without * interleaving them. *

- * + * *

*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
@@ -1131,19 +1165,19 @@ public static Observable concat(@NonNull ObservableSource so * * @param the common element base type * @param source1 - * an ObservableSource to be concatenated + * an {@code ObservableSource} to be concatenated * @param source2 - * an ObservableSource to be concatenated + * an {@code ObservableSource} to be concatenated * @param source3 - * an ObservableSource to be concatenated - * @return an Observable that emits items emitted by the three source ObservableSources, one after the other, - * without interleaving them + * an {@code ObservableSource} to be concatenated + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} * @see ReactiveX operators documentation: Concat */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable concat( + public static <@NonNull T> Observable concat( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3) { Objects.requireNonNull(source1, "source1 is null"); @@ -1153,10 +1187,10 @@ public static Observable concat( } /** - * Returns an Observable that emits the items emitted by four ObservableSources, one after the other, without + * Returns an {@code Observable} that emits the items emitted by four {@link ObservableSource}s, one after the other, without * interleaving them. *

- * + * *

*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
@@ -1164,21 +1198,21 @@ public static Observable concat( * * @param the common element base type * @param source1 - * an ObservableSource to be concatenated + * an {@code ObservableSource} to be concatenated * @param source2 - * an ObservableSource to be concatenated + * an {@code ObservableSource} to be concatenated * @param source3 - * an ObservableSource to be concatenated + * an {@code ObservableSource} to be concatenated * @param source4 - * an ObservableSource to be concatenated - * @return an Observable that emits items emitted by the four source ObservableSources, one after the other, - * without interleaving them + * an {@code ObservableSource} to be concatenated + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} * @see ReactiveX operators documentation: Concat */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable concat( + public static <@NonNull T> Observable concat( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4) { Objects.requireNonNull(source1, "source1 is null"); @@ -1189,26 +1223,27 @@ public static Observable concat( } /** - * Concatenates a variable number of ObservableSource sources. + * Concatenates a variable number of {@link ObservableSource} sources. *

- * Note: named this way because of overload conflict with concat(ObservableSource<ObservableSource>) + * Note: named this way because of overload conflict with {@code concat(ObservableSource)} *

- * + * *

*
Scheduler:
*
{@code concatArray} does not operate by default on a particular {@link Scheduler}.
*
* @param sources the array of sources * @param the common base value type - * @return the new Observable instance - * @throws NullPointerException if sources is null + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull @SafeVarargs - public static Observable concatArray(@NonNull ObservableSource... sources) { + public static <@NonNull T> Observable concatArray(@NonNull ObservableSource... sources) { + Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { return empty(); } @@ -1219,24 +1254,25 @@ public static Observable concatArray(@NonNull ObservableSource - * + * *
*
Scheduler:
*
{@code concatArrayDelayError} does not operate by default on a particular {@link Scheduler}.
*
* @param sources the array of sources * @param the common base value type - * @return the new Observable instance - * @throws NullPointerException if sources is null + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull @SafeVarargs - public static Observable concatArrayDelayError(@NonNull ObservableSource... sources) { + public static <@NonNull T> Observable concatArrayDelayError(@NonNull ObservableSource... sources) { + Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { return empty(); } @@ -1249,48 +1285,51 @@ public static Observable concatArrayDelayError(@NonNull ObservableSource< } /** - * Concatenates an array of ObservableSources eagerly into a single stream of values. + * Concatenates an array of {@link ObservableSource}s eagerly into a single stream of values. *

- * + * *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source ObservableSources. The operator buffers the values emitted by these ObservableSources and then drains them + * {@code ObservableSource}s. The operator buffers the values emitted by these {@code ObservableSource}s and then drains them * in order, each one after the previous one completes. *

*
Scheduler:
*
This method does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources an array of ObservableSources that need to be eagerly concatenated - * @return the new ObservableSource instance with the specified concatenation behavior + * @param sources an array of {@code ObservableSource}s that need to be eagerly concatenated + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs @NonNull - public static Observable concatArrayEager(@NonNull ObservableSource... sources) { + public static <@NonNull T> Observable concatArrayEager(@NonNull ObservableSource... sources) { return concatArrayEager(bufferSize(), bufferSize(), sources); } /** - * Concatenates an array of ObservableSources eagerly into a single stream of values. + * Concatenates an array of {@link ObservableSource}s eagerly into a single stream of values. *

* *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source ObservableSources. The operator buffers the values emitted by these ObservableSources and then drains them + * {@code ObservableSource}s. The operator buffers the values emitted by these {@code ObservableSource}s and then drains them * in order, each one after the previous one completes. *

*
Scheduler:
*
This method does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources an array of ObservableSources that need to be eagerly concatenated + * @param sources an array of {@code ObservableSource}s that need to be eagerly concatenated * @param maxConcurrency the maximum number of concurrent subscriptions at a time, {@link Integer#MAX_VALUE} * is interpreted as indication to subscribe to all sources at once - * @param prefetch the number of elements to prefetch from each ObservableSource source - * @return the new ObservableSource instance with the specified concatenation behavior + * @param bufferSize the number of elements expected from each {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive * @since 2.0 */ @SuppressWarnings({ "rawtypes", "unchecked" }) @@ -1298,8 +1337,8 @@ public static Observable concatArrayEager(@NonNull ObservableSource Observable concatArrayEager(int maxConcurrency, int prefetch, @NonNull ObservableSource... sources) { - return fromArray(sources).concatMapEagerDelayError((Function)Functions.identity(), false, maxConcurrency, prefetch); + public static <@NonNull T> Observable concatArrayEager(int maxConcurrency, int bufferSize, @NonNull ObservableSource... sources) { + return fromArray(sources).concatMapEagerDelayError((Function)Functions.identity(), false, maxConcurrency, bufferSize); } /** @@ -1309,7 +1348,7 @@ public static Observable concatArrayEager(int maxConcurrency, int prefetc * *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source {@code ObservableSource}s. The operator buffers the values emitted by these {@code ObservableSource}s + * {@code ObservableSource}s. The operator buffers the values emitted by these {@code ObservableSource}s * and then drains them in order, each one after the previous one completes. *

*
Scheduler:
@@ -1317,14 +1356,15 @@ public static Observable concatArrayEager(int maxConcurrency, int prefetc *
* @param the value type * @param sources an array of {@code ObservableSource}s that need to be eagerly concatenated - * @return the new Observable instance with the specified concatenation behavior + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.2.1 - experimental */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs @NonNull - public static Observable concatArrayEagerDelayError(@NonNull ObservableSource... sources) { + public static <@NonNull T> Observable concatArrayEagerDelayError(@NonNull ObservableSource... sources) { return concatArrayEagerDelayError(bufferSize(), bufferSize(), sources); } @@ -1335,7 +1375,7 @@ public static Observable concatArrayEagerDelayError(@NonNull ObservableSo * *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source {@code ObservableSource}s. The operator buffers the values emitted by these {@code ObservableSource}s + * {@code ObservableSource}s. The operator buffers the values emitted by these {@code ObservableSource}s * and then drains them in order, each one after the previous one completes. *

*
Scheduler:
@@ -1345,8 +1385,10 @@ public static Observable concatArrayEagerDelayError(@NonNull ObservableSo * @param sources an array of {@code ObservableSource}s that need to be eagerly concatenated * @param maxConcurrency the maximum number of concurrent subscriptions at a time, {@link Integer#MAX_VALUE} * is interpreted as indication to subscribe to all sources at once - * @param prefetch the number of elements to prefetch from each {@code ObservableSource} source - * @return the new Observable instance with the specified concatenation behavior + * @param bufferSize the number of elements expected from each {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive * @since 2.2.1 - experimental */ @SuppressWarnings({ "rawtypes", "unchecked" }) @@ -1354,186 +1396,316 @@ public static Observable concatArrayEagerDelayError(@NonNull ObservableSo @SchedulerSupport(SchedulerSupport.NONE) @NonNull @SafeVarargs - public static Observable concatArrayEagerDelayError(int maxConcurrency, int prefetch, @NonNull ObservableSource... sources) { - return fromArray(sources).concatMapEagerDelayError((Function)Functions.identity(), true, maxConcurrency, prefetch); + public static <@NonNull T> Observable concatArrayEagerDelayError(int maxConcurrency, int bufferSize, @NonNull ObservableSource... sources) { + return fromArray(sources).concatMapEagerDelayError((Function)Functions.identity(), true, maxConcurrency, bufferSize); } /** - * Concatenates the Iterable sequence of ObservableSources into a single sequence by subscribing to each ObservableSource, - * one after the other, one at a time and delays any errors till the all inner ObservableSources terminate. + * Concatenates the {@link Iterable} sequence of {@link ObservableSource}s into a single {@code Observable} sequence + * by subscribing to each {@code ObservableSource}, one after the other, one at a time and delays any errors till + * the all inner {@code ObservableSource}s terminate. *

- * + * *

*
Scheduler:
*
{@code concatDelayError} does not operate by default on a particular {@link Scheduler}.
*
* * @param the common element base type - * @param sources the Iterable sequence of ObservableSources - * @return the new ObservableSource with the concatenating behavior + * @param sources the {@code Iterable} sequence of {@code ObservableSource}s + * @return the new {@code Observable} with the concatenating behavior + * @throws NullPointerException if {@code sources} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable concatDelayError(@NonNull Iterable> sources) { + public static <@NonNull T> Observable concatDelayError(@NonNull Iterable<@NonNull ? extends ObservableSource> sources) { Objects.requireNonNull(sources, "sources is null"); return concatDelayError(fromIterable(sources)); } /** - * Concatenates the ObservableSource sequence of ObservableSources into a single sequence by subscribing to each inner ObservableSource, - * one after the other, one at a time and delays any errors till the all inner and the outer ObservableSources terminate. + * Concatenates the {@link ObservableSource} sequence of {@code ObservableSource}s into a single {@code Observable} sequence + * by subscribing to each inner {@code ObservableSource}, one after the other, one at a time and delays any errors till the + * all inner and the outer {@code ObservableSource}s terminate. *

- * + * *

*
Scheduler:
*
{@code concatDelayError} does not operate by default on a particular {@link Scheduler}.
*
* * @param the common element base type - * @param sources the ObservableSource sequence of ObservableSources - * @return the new ObservableSource with the concatenating behavior + * @param sources the {@code ObservableSource} sequence of {@code ObservableSource}s + * @return the new {@code Observable} with the concatenating behavior + * @throws NullPointerException if {@code sources} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable concatDelayError(@NonNull ObservableSource> sources) { + public static <@NonNull T> Observable concatDelayError(@NonNull ObservableSource> sources) { return concatDelayError(sources, bufferSize(), true); } /** - * Concatenates the ObservableSource sequence of ObservableSources into a single sequence by subscribing to each inner ObservableSource, - * one after the other, one at a time and delays any errors till the all inner and the outer ObservableSources terminate. + * Concatenates the {@link ObservableSource} sequence of {@code ObservableSource}s into a single sequence by subscribing to each inner {@code ObservableSource}, + * one after the other, one at a time and delays any errors till the all inner and the outer {@code ObservableSource}s terminate. *

- * + * *

*
Scheduler:
*
{@code concatDelayError} does not operate by default on a particular {@link Scheduler}.
*
* * @param the common element base type - * @param sources the ObservableSource sequence of ObservableSources - * @param prefetch the number of elements to prefetch from the outer ObservableSource - * @param tillTheEnd if true exceptions from the outer and all inner ObservableSources are delayed to the end - * if false, exception from the outer ObservableSource is delayed till the current ObservableSource terminates - * @return the new ObservableSource with the concatenating behavior + * @param sources the {@code ObservableSource} sequence of {@code ObservableSource}s + * @param bufferSize the number of inner {@code ObservableSource}s expected to be buffered + * @param tillTheEnd if {@code true}, exceptions from the outer and all inner {@code ObservableSource}s are delayed to the end + * if {@code false}, exception from the outer {@code ObservableSource} is delayed till the active {@code ObservableSource} terminates + * @return the new {@code Observable} with the concatenating behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive */ @SuppressWarnings({ "rawtypes", "unchecked" }) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable concatDelayError(@NonNull ObservableSource> sources, int prefetch, boolean tillTheEnd) { + public static <@NonNull T> Observable concatDelayError(@NonNull ObservableSource> sources, int bufferSize, boolean tillTheEnd) { Objects.requireNonNull(sources, "sources is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch is null"); - return RxJavaPlugins.onAssembly(new ObservableConcatMap(sources, Functions.identity(), prefetch, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY)); + ObjectHelper.verifyPositive(bufferSize, "bufferSize is null"); + return RxJavaPlugins.onAssembly(new ObservableConcatMap(sources, Functions.identity(), bufferSize, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY)); } /** - * Concatenates an ObservableSource sequence of ObservableSources eagerly into a single stream of values. + * Concatenates a sequence of {@link ObservableSource}s eagerly into a single stream of values. *

- * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * emitted source ObservableSources as they are observed. The operator buffers the values emitted by these - * ObservableSources and then drains them in order, each one after the previous one completes. + * *

- * + * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * {@code ObservableSource}s. The operator buffers the values emitted by these {@code ObservableSource}s and then drains them + * in order, each one after the previous one completes. *

*
Scheduler:
*
This method does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources a sequence of ObservableSources that need to be eagerly concatenated - * @return the new ObservableSource instance with the specified concatenation behavior + * @param sources a sequence of {@code ObservableSource}s that need to be eagerly concatenated + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable concatEager(@NonNull ObservableSource> sources) { + public static <@NonNull T> Observable concatEager(@NonNull Iterable<@NonNull ? extends ObservableSource> sources) { return concatEager(sources, bufferSize(), bufferSize()); } /** - * Concatenates an ObservableSource sequence of ObservableSources eagerly into a single stream of values. + * Concatenates a sequence of {@link ObservableSource}s eagerly into a single stream of values and + * runs a limited number of inner sequences at once. *

- * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * emitted source ObservableSources as they are observed. The operator buffers the values emitted by these - * ObservableSources and then drains them in order, each one after the previous one completes. + * *

- * + * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * {@code ObservableSource}s. The operator buffers the values emitted by these {@code ObservableSource}s and then drains them + * in order, each one after the previous one completes. *

*
Scheduler:
*
This method does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources a sequence of ObservableSources that need to be eagerly concatenated - * @param maxConcurrency the maximum number of concurrently running inner ObservableSources; {@link Integer#MAX_VALUE} - * is interpreted as all inner ObservableSources can be active at the same time - * @param prefetch the number of elements to prefetch from each inner ObservableSource source - * @return the new ObservableSource instance with the specified concatenation behavior + * @param sources a sequence of {@code ObservableSource}s that need to be eagerly concatenated + * @param maxConcurrency the maximum number of concurrently running inner {@code ObservableSource}s; {@link Integer#MAX_VALUE} + * is interpreted as all inner {@code ObservableSource}s can be active at the same time + * @param bufferSize the number of elements expected from each inner {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive * @since 2.0 */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable concatEager(@NonNull ObservableSource> sources, int maxConcurrency, int prefetch) { - return wrap(sources).concatMapEager((Function)Functions.identity(), maxConcurrency, prefetch); + public static <@NonNull T> Observable concatEager(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, int maxConcurrency, int bufferSize) { + return fromIterable(sources).concatMapEagerDelayError((Function)Functions.identity(), false, maxConcurrency, bufferSize); } /** - * Concatenates a sequence of ObservableSources eagerly into a single stream of values. + * Concatenates an {@link ObservableSource} sequence of {@code ObservableSource}s eagerly into a single stream of values. *

- * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source ObservableSources. The operator buffers the values emitted by these ObservableSources and then drains them - * in order, each one after the previous one completes. + * *

- * + * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * emitted source {@code ObservableSource}s as they are observed. The operator buffers the values emitted by these + * {@code ObservableSource}s and then drains them in order, each one after the previous one completes. *

*
Scheduler:
*
This method does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources a sequence of ObservableSources that need to be eagerly concatenated - * @return the new ObservableSource instance with the specified concatenation behavior + * @param sources a sequence of {@code ObservableSource}s that need to be eagerly concatenated + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable concatEager(@NonNull Iterable> sources) { + public static <@NonNull T> Observable concatEager(@NonNull ObservableSource> sources) { return concatEager(sources, bufferSize(), bufferSize()); } /** - * Concatenates a sequence of ObservableSources eagerly into a single stream of values. + * Concatenates an {@link ObservableSource} sequence of {@code ObservableSource}s eagerly into a single stream of values + * and runs a limited number of inner sequences at once. + * + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * emitted source {@code ObservableSource}s as they are observed. The operator buffers the values emitted by these + * {@code ObservableSource}s and then drains them in order, each one after the previous one completes. + *

+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code ObservableSource}s that need to be eagerly concatenated + * @param maxConcurrency the maximum number of concurrently running inner {@code ObservableSource}s; {@link Integer#MAX_VALUE} + * is interpreted as all inner {@code ObservableSource}s can be active at the same time + * @param bufferSize the number of inner {@code ObservableSource} expected to be buffered + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive + * @since 2.0 + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Observable concatEager(@NonNull ObservableSource> sources, int maxConcurrency, int bufferSize) { + return wrap(sources).concatMapEager((Function)Functions.identity(), maxConcurrency, bufferSize); + } + + /** + * Concatenates a sequence of {@link ObservableSource}s eagerly into a single stream of values, + * delaying errors until all the inner sequences terminate. + *

+ * *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source ObservableSources. The operator buffers the values emitted by these ObservableSources and then drains them + * {@code ObservableSource}s. The operator buffers the values emitted by these {@code ObservableSource}s and then drains them * in order, each one after the previous one completes. + *

+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code ObservableSource}s that need to be eagerly concatenated + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Observable concatEagerDelayError(@NonNull Iterable<@NonNull ? extends ObservableSource> sources) { + return concatEagerDelayError(sources, bufferSize(), bufferSize()); + } + + /** + * Concatenates a sequence of {@link ObservableSource}s eagerly into a single stream of values, + * delaying errors until all the inner sequences terminate and runs a limited number of inner + * sequences at once. + *

+ * *

- * + * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * {@code ObservableSource}s. The operator buffers the values emitted by these {@code ObservableSource}s and then drains them + * in order, each one after the previous one completes. *

*
Scheduler:
*
This method does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources a sequence of ObservableSources that need to be eagerly concatenated - * @param maxConcurrency the maximum number of concurrently running inner ObservableSources; {@link Integer#MAX_VALUE} - * is interpreted as all inner ObservableSources can be active at the same time - * @param prefetch the number of elements to prefetch from each inner ObservableSource source - * @return the new ObservableSource instance with the specified concatenation behavior - * @since 2.0 + * @param sources a sequence of {@code ObservableSource}s that need to be eagerly concatenated + * @param maxConcurrency the maximum number of concurrently running inner {@code ObservableSource}s; {@link Integer#MAX_VALUE} + * is interpreted as all inner {@code ObservableSource}s can be active at the same time + * @param bufferSize the number of elements expected from each inner {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive + * @since 3.0.0 */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable concatEager(@NonNull Iterable> sources, int maxConcurrency, int prefetch) { - return fromIterable(sources).concatMapEagerDelayError((Function)Functions.identity(), false, maxConcurrency, prefetch); + public static <@NonNull T> Observable concatEagerDelayError(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, int maxConcurrency, int bufferSize) { + return fromIterable(sources).concatMapEagerDelayError((Function)Functions.identity(), true, maxConcurrency, bufferSize); } /** - * Provides an API (via a cold Observable) that bridges the reactive world with the callback-style world. + * Concatenates an {@link ObservableSource} sequence of {@code ObservableSource}s eagerly into a single stream of values, + * delaying errors until all the inner and the outer sequence terminate. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * emitted source {@code ObservableSource}s as they are observed. The operator buffers the values emitted by these + * {@code ObservableSource}s and then drains them in order, each one after the previous one completes. + *

+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code ObservableSource}s that need to be eagerly concatenated + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Observable concatEagerDelayError(@NonNull ObservableSource> sources) { + return concatEagerDelayError(sources, bufferSize(), bufferSize()); + } + + /** + * Concatenates an {@link ObservableSource} sequence of {@code ObservableSource}s eagerly into a single stream of values, + * delaying errors until all the inner and the outer sequence terminate and runs a limited number of inner sequences at once. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * emitted source {@code ObservableSource}s as they are observed. The operator buffers the values emitted by these + * {@code ObservableSource}s and then drains them in order, each one after the previous one completes. + *

+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code ObservableSource}s that need to be eagerly concatenated + * @param maxConcurrency the maximum number of concurrently running inner {@code ObservableSource}s; {@link Integer#MAX_VALUE} + * is interpreted as all inner {@code ObservableSource}s can be active at the same time + * @param bufferSize the number of inner {@code ObservableSource} expected to be buffered + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive + * @since 3.0.0 + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Observable concatEagerDelayError(@NonNull ObservableSource> sources, int maxConcurrency, int bufferSize) { + return wrap(sources).concatMapEagerDelayError((Function)Functions.identity(), true, maxConcurrency, bufferSize); + } + + /** + * Provides an API (via a cold {@code Observable}) that bridges the reactive world with the callback-style world. *

* Example: *


@@ -1563,12 +1735,12 @@ public static  Observable concatEager(@NonNull Iterable
-     * 
+     * 
      * 

- * You should call the ObservableEmitter's onNext, onError and onComplete methods in a serialized fashion. The + * You should call the {@code ObservableEmitter}'s {@code onNext}, {@code onError} and {@code onComplete} methods in a serialized fashion. The * rest of its methods are thread-safe. *

*
Scheduler:
@@ -1576,8 +1748,9 @@ public static Observable concatEager(@NonNull Iterable * * @param the element type - * @param source the emitter that is called when an Observer subscribes to the returned {@code Observable} - * @return the new Observable instance + * @param source the emitter that is called when an {@code Observer} subscribes to the returned {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source} is {@code null} * @see ObservableOnSubscribe * @see ObservableEmitter * @see Cancellable @@ -1585,20 +1758,20 @@ public static Observable concatEager(@NonNull Iterable Observable create(@NonNull ObservableOnSubscribe source) { + public static <@NonNull T> Observable create(@NonNull ObservableOnSubscribe source) { Objects.requireNonNull(source, "source is null"); return RxJavaPlugins.onAssembly(new ObservableCreate<>(source)); } /** - * Returns an Observable that calls an ObservableSource factory to create an ObservableSource for each new Observer - * that subscribes. That is, for each subscriber, the actual ObservableSource that subscriber observes is + * Returns an {@code Observable} that calls an {@link ObservableSource} factory to create an {@code ObservableSource} for each new {@link Observer} + * that subscribes. That is, for each subscriber, the actual {@code ObservableSource} that subscriber observes is * determined by the factory function. *

- * + * *

- * The defer Observer allows you to defer or delay emitting items from an ObservableSource until such time as an - * Observer subscribes to the ObservableSource. This allows an {@link Observer} to easily obtain updates or a + * The {@code defer} operator allows you to defer or delay emitting items from an {@code ObservableSource} until such time as an + * {@code Observer} subscribes to the {@code ObservableSource}. This allows an {@code Observer} to easily obtain updates or a * refreshed version of the sequence. *

*
Scheduler:
@@ -1606,102 +1779,131 @@ public static Observable create(@NonNull ObservableOnSubscribe source) *
* * @param supplier - * the ObservableSource factory function to invoke for each {@link Observer} that subscribes to the - * resulting ObservableSource + * the {@code ObservableSource} factory function to invoke for each {@code Observer} that subscribes to the + * resulting {@code Observable} * @param - * the type of the items emitted by the ObservableSource - * @return an Observable whose {@link Observer}s' subscriptions trigger an invocation of the given - * ObservableSource factory function + * the type of the items emitted by the {@code ObservableSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code supplier} is {@code null} * @see ReactiveX operators documentation: Defer */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable defer(@NonNull Supplier> supplier) { + public static <@NonNull T> Observable defer(@NonNull Supplier> supplier) { Objects.requireNonNull(supplier, "supplier is null"); return RxJavaPlugins.onAssembly(new ObservableDefer<>(supplier)); } /** - * Returns an Observable that emits no items to the {@link Observer} and immediately invokes its + * Returns an {@code Observable} that emits no items to the {@link Observer} and immediately invokes its * {@link Observer#onComplete onComplete} method. *

- * + * *

*
Scheduler:
*
{@code empty} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of the items (ostensibly) emitted by the ObservableSource - * @return an Observable that emits no items to the {@link Observer} but immediately invokes the - * {@link Observer}'s {@link Observer#onComplete() onComplete} method + * the type of the items (ostensibly) emitted by the {@code Observable} + * @return the shared {@code Observable} instance * @see ReactiveX operators documentation: Empty */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @SuppressWarnings("unchecked") @NonNull - public static Observable empty() { + public static <@NonNull T> Observable empty() { return RxJavaPlugins.onAssembly((Observable) ObservableEmpty.INSTANCE); } /** - * Returns an Observable that invokes an {@link Observer}'s {@link Observer#onError onError} method when the - * Observer subscribes to it. + * Returns an {@code Observable} that invokes an {@link Observer}'s {@link Observer#onError onError} method when the + * {@code Observer} subscribes to it. *

- * + * *

*
Scheduler:
*
{@code error} does not operate by default on a particular {@link Scheduler}.
*
* - * @param errorSupplier - * a Supplier factory to return a Throwable for each individual Observer + * @param supplier + * a {@link Supplier} factory to return a {@link Throwable} for each individual {@code Observer} * @param - * the type of the items (ostensibly) emitted by the ObservableSource - * @return an Observable that invokes the {@link Observer}'s {@link Observer#onError onError} method when - * the Observer subscribes to it + * the type of the items (ostensibly) emitted by the {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code supplier} is {@code null} * @see ReactiveX operators documentation: Throw */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable error(@NonNull Supplier errorSupplier) { - Objects.requireNonNull(errorSupplier, "errorSupplier is null"); - return RxJavaPlugins.onAssembly(new ObservableError<>(errorSupplier)); + public static <@NonNull T> Observable error(@NonNull Supplier supplier) { + Objects.requireNonNull(supplier, "supplier is null"); + return RxJavaPlugins.onAssembly(new ObservableError<>(supplier)); } /** - * Returns an Observable that invokes an {@link Observer}'s {@link Observer#onError onError} method when the - * Observer subscribes to it. + * Returns an {@code Observable} that invokes an {@link Observer}'s {@link Observer#onError onError} method when the + * {@code Observer} subscribes to it. *

- * + * *

*
Scheduler:
*
{@code error} does not operate by default on a particular {@link Scheduler}.
*
* - * @param exception - * the particular Throwable to pass to {@link Observer#onError onError} + * @param throwable + * the particular {@link Throwable} to pass to {@link Observer#onError onError} * @param - * the type of the items (ostensibly) emitted by the ObservableSource - * @return an Observable that invokes the {@link Observer}'s {@link Observer#onError onError} method when - * the Observer subscribes to it + * the type of the items (ostensibly) emitted by the {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code throwable} is {@code null} * @see ReactiveX operators documentation: Throw */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable error(@NonNull Throwable exception) { - Objects.requireNonNull(exception, "exception is null"); - return error(Functions.justSupplier(exception)); + public static <@NonNull T> Observable error(@NonNull Throwable throwable) { + Objects.requireNonNull(throwable, "throwable is null"); + return error(Functions.justSupplier(throwable)); + } + + /** + * Returns an {@code Observable} instance that runs the given {@link Action} for each {@link Observer} and + * emits either its exception or simply completes. + *

+ * + *

+ *
Scheduler:
+ *
{@code fromAction} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If the {@code Action} throws an exception, the respective {@link Throwable} is + * delivered to the downstream via {@link Observer#onError(Throwable)}, + * except when the downstream has canceled the resulting {@code Observable} source. + * In this latter case, the {@code Throwable} is delivered to the global error handler via + * {@link RxJavaPlugins#onError(Throwable)} as an {@link io.reactivex.rxjava3.exceptions.UndeliverableException UndeliverableException}. + *
+ *
+ * @param the target type + * @param action the {@code Action} to run for each {@code Observer} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code action} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Observable fromAction(@NonNull Action action) { + Objects.requireNonNull(action, "action is null"); + return RxJavaPlugins.onAssembly(new ObservableFromAction<>(action)); } /** - * Converts an Array into an ObservableSource that emits the items in the Array. + * Converts an array into an {@link ObservableSource} that emits the items in the array. *

- * + * *

*
Scheduler:
*
{@code fromArray} does not operate by default on a particular {@link Scheduler}.
@@ -1710,15 +1912,16 @@ public static Observable error(@NonNull Throwable exception) { * @param items * the array of elements * @param - * the type of items in the Array and the type of items to be emitted by the resulting ObservableSource - * @return an Observable that emits each item in the source Array + * the type of items in the array and the type of items to be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code items} is {@code null} * @see ReactiveX operators documentation: From */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull @SafeVarargs - public static Observable fromArray(@NonNull T... items) { + public static <@NonNull T> Observable fromArray(@NonNull T... items) { Objects.requireNonNull(items, "items is null"); if (items.length == 0) { return empty(); @@ -1730,30 +1933,31 @@ public static Observable fromArray(@NonNull T... items) { } /** - * Returns an Observable that, when an observer subscribes to it, invokes a function you specify and then + * Returns an {@code Observable} that, when an observer subscribes to it, invokes a function you specify and then * emits the value returned from that function. *

- * + * *

* This allows you to defer the execution of the function you specify until an observer subscribes to the - * ObservableSource. That is to say, it makes the function "lazy." + * {@code Observable}. That is to say, it makes the function "lazy." *

*
Scheduler:
*
{@code fromCallable} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
*
If the {@link Callable} throws an exception, the respective {@link Throwable} is * delivered to the downstream via {@link Observer#onError(Throwable)}, - * except when the downstream has disposed this {@code Observable} source. + * except when the downstream has disposed the current {@code Observable} source. * In this latter case, the {@code Throwable} is delivered to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} as an {@link io.reactivex.rxjava3.exceptions.UndeliverableException UndeliverableException}. + * {@link RxJavaPlugins#onError(Throwable)} as an {@link UndeliverableException}. *
*
- * @param supplier + * @param callable * a function, the execution of which should be deferred; {@code fromCallable} will invoke this - * function only when an observer subscribes to the ObservableSource that {@code fromCallable} returns + * function only when an observer subscribes to the {@code Observable} that {@code fromCallable} returns * @param - * the type of the item emitted by the ObservableSource - * @return an Observable whose {@link Observer}s' subscriptions trigger an invocation of the given function + * the type of the item returned by the {@code Callable} and emitted by the {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code callable} is {@code null} * @see #defer(Supplier) * @see #fromSupplier(Supplier) * @since 2.0 @@ -1761,201 +1965,179 @@ public static Observable fromArray(@NonNull T... items) { @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable fromCallable(@NonNull Callable supplier) { - Objects.requireNonNull(supplier, "supplier is null"); - return RxJavaPlugins.onAssembly(new ObservableFromCallable<>(supplier)); + public static <@NonNull T> Observable fromCallable(@NonNull Callable callable) { + Objects.requireNonNull(callable, "callable is null"); + return RxJavaPlugins.onAssembly(new ObservableFromCallable<>(callable)); } /** - * Converts a {@link Future} into an ObservableSource. - *

- * - *

- * You can convert any object that supports the {@link Future} interface into an ObservableSource that emits the - * return value of the {@link Future#get} method of that object, by passing the object into the {@code from} - * method. + * Wraps a {@link CompletableSource} into an {@code Observable}. *

- * Important note: This ObservableSource is blocking; you cannot dispose it. - *

- * Unlike 1.x, disposing the Observable won't cancel the future. If necessary, one can use composition to achieve the - * cancellation effect: {@code futureObservableSource.doOnDispose(() -> future.cancel(true));}. + * *

*
Scheduler:
- *
{@code fromFuture} does not operate by default on a particular {@link Scheduler}.
+ *
{@code fromCompletable} does not operate by default on a particular {@link Scheduler}.
*
- * - * @param future - * the source {@link Future} - * @param - * the type of object that the {@link Future} returns, and also the type of item to be emitted by - * the resulting ObservableSource - * @return an Observable that emits the item from the source {@link Future} - * @see ReactiveX operators documentation: From + * @param the target type + * @param completableSource the {@code CompletableSource} to convert from + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code completableSource} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable fromFuture(@NonNull Future future) { - Objects.requireNonNull(future, "future is null"); - return RxJavaPlugins.onAssembly(new ObservableFromFuture<>(future, 0L, null)); + public static <@NonNull T> Observable fromCompletable(@NonNull CompletableSource completableSource) { + Objects.requireNonNull(completableSource, "completableSource is null"); + return RxJavaPlugins.onAssembly(new ObservableFromCompletable<>(completableSource)); } /** - * Converts a {@link Future} into an ObservableSource, with a timeout on the Future. + * Converts a {@link Future} into an {@code Observable}. *

- * + * *

- * You can convert any object that supports the {@link Future} interface into an ObservableSource that emits the - * return value of the {@link Future#get} method of that object, by passing the object into the {@code from} - * method. + * The operator calls {@link Future#get()}, which is a blocking method, on the subscription thread. + * It is recommended applying {@link #subscribeOn(Scheduler)} to move this blocking wait to a + * background thread, and if the {@link Scheduler} supports it, interrupt the wait when the flow + * is disposed. *

- * Unlike 1.x, disposing the Observable won't cancel the future. If necessary, one can use composition to achieve the + * Unlike 1.x, disposing the {@code Observable} won't cancel the future. If necessary, one can use composition to achieve the * cancellation effect: {@code futureObservableSource.doOnDispose(() -> future.cancel(true));}. *

- * Important note: This ObservableSource is blocking; you cannot dispose it. + * Also note that this operator will consume a {@link CompletionStage}-based {@code Future} subclass (such as + * {@link CompletableFuture}) in a blocking manner as well. Use the {@link #fromCompletionStage(CompletionStage)} + * operator to convert and consume such sources in a non-blocking fashion instead. *

*
Scheduler:
- *
{@code fromFuture} does not operate by default on a particular {@link Scheduler}.
+ *
{@code fromFuture} does not operate by default on a particular {@code Scheduler}.
*
* * @param future - * the source {@link Future} - * @param timeout - * the maximum time to wait before calling {@code get} - * @param unit - * the {@link TimeUnit} of the {@code timeout} argument + * the source {@code Future} * @param - * the type of object that the {@link Future} returns, and also the type of item to be emitted by - * the resulting ObservableSource - * @return an Observable that emits the item from the source {@link Future} + * the type of object that the {@code Future} returns, and also the type of item to be emitted by + * the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code future} is {@code null} * @see ReactiveX operators documentation: From + * @see #fromCompletionStage(CompletionStage) */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable fromFuture(@NonNull Future future, long timeout, @NonNull TimeUnit unit) { + public static <@NonNull T> Observable fromFuture(@NonNull Future future) { Objects.requireNonNull(future, "future is null"); - Objects.requireNonNull(unit, "unit is null"); - return RxJavaPlugins.onAssembly(new ObservableFromFuture<>(future, timeout, unit)); + return RxJavaPlugins.onAssembly(new ObservableFromFuture<>(future, 0L, null)); } /** - * Converts a {@link Future} into an ObservableSource, with a timeout on the Future. + * Converts a {@link Future} into an {@code Observable}, with a timeout on the {@code Future}. *

- * + * *

- * You can convert any object that supports the {@link Future} interface into an ObservableSource that emits the - * return value of the {@link Future#get} method of that object, by passing the object into the {@code from} - * method. + * The operator calls {@link Future#get(long, TimeUnit)}, which is a blocking method, on the subscription thread. + * It is recommended applying {@link #subscribeOn(Scheduler)} to move this blocking wait to a + * background thread, and if the {@link Scheduler} supports it, interrupt the wait when the flow + * is disposed. *

- * Unlike 1.x, disposing the Observable won't cancel the future. If necessary, one can use composition to achieve the + * Unlike 1.x, disposing the {@code Observable} won't cancel the future. If necessary, one can use composition to achieve the * cancellation effect: {@code futureObservableSource.doOnDispose(() -> future.cancel(true));}. *

- * Important note: This ObservableSource is blocking; you cannot dispose it. + * Also note that this operator will consume a {@link CompletionStage}-based {@code Future} subclass (such as + * {@link CompletableFuture}) in a blocking manner as well. Use the {@link #fromCompletionStage(CompletionStage)} + * operator to convert and consume such sources in a non-blocking fashion instead. *

*
Scheduler:
- *
{@code fromFuture} does not operate by default on a particular {@link Scheduler}.
+ *
{@code fromFuture} does not operate by default on a particular {@code Scheduler}.
*
* * @param future - * the source {@link Future} + * the source {@code Future} * @param timeout * the maximum time to wait before calling {@code get} * @param unit * the {@link TimeUnit} of the {@code timeout} argument - * @param scheduler - * the {@link Scheduler} to wait for the Future on. Use a Scheduler such as - * {@link Schedulers#io()} that can block and wait on the Future * @param - * the type of object that the {@link Future} returns, and also the type of item to be emitted by - * the resulting ObservableSource - * @return an Observable that emits the item from the source {@link Future} + * the type of object that the {@code Future} returns, and also the type of item to be emitted by + * the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code future} or {@code unit} is {@code null} * @see ReactiveX operators documentation: From + * @see #fromCompletionStage(CompletionStage) */ @CheckReturnValue @NonNull - @SchedulerSupport(SchedulerSupport.CUSTOM) - public static Observable fromFuture(@NonNull Future future, long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - Objects.requireNonNull(scheduler, "scheduler is null"); - Observable o = fromFuture(future, timeout, unit); - return o.subscribeOn(scheduler); + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Observable fromFuture(@NonNull Future future, long timeout, @NonNull TimeUnit unit) { + Objects.requireNonNull(future, "future is null"); + Objects.requireNonNull(unit, "unit is null"); + return RxJavaPlugins.onAssembly(new ObservableFromFuture<>(future, timeout, unit)); } /** - * Converts a {@link Future}, operating on a specified {@link Scheduler}, into an ObservableSource. - *

- * + * Converts an {@link Iterable} sequence into an {@code Observable} that emits the items in the sequence. *

- * You can convert any object that supports the {@link Future} interface into an ObservableSource that emits the - * return value of the {@link Future#get} method of that object, by passing the object into the {@code from} - * method. - *

- * Unlike 1.x, disposing the Observable won't cancel the future. If necessary, one can use composition to achieve the - * cancellation effect: {@code futureObservableSource.doOnDispose(() -> future.cancel(true));}. + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
{@code fromIterable} does not operate by default on a particular {@link Scheduler}.
*
* - * @param future - * the source {@link Future} - * @param scheduler - * the {@link Scheduler} to wait for the Future on. Use a Scheduler such as - * {@link Schedulers#io()} that can block and wait on the Future + * @param source + * the source {@code Iterable} sequence * @param - * the type of object that the {@link Future} returns, and also the type of item to be emitted by - * the resulting ObservableSource - * @return an Observable that emits the item from the source {@link Future} + * the type of items in the {@code Iterable} sequence and the type of items to be emitted by the + * resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source} is {@code null} * @see ReactiveX operators documentation: From + * @see #fromStream(Stream) */ @CheckReturnValue @NonNull - @SchedulerSupport(SchedulerSupport.CUSTOM) - public static Observable fromFuture(@NonNull Future future, @NonNull Scheduler scheduler) { - Objects.requireNonNull(scheduler, "scheduler is null"); - Observable o = fromFuture(future); - return o.subscribeOn(scheduler); + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Observable fromIterable(@NonNull Iterable source) { + Objects.requireNonNull(source, "source is null"); + return RxJavaPlugins.onAssembly(new ObservableFromIterable<>(source)); } /** - * Converts an {@link Iterable} sequence into an ObservableSource that emits the items in the sequence. + * Returns an {@code Observable} instance that when subscribed to, subscribes to the {@link MaybeSource} instance and + * emits {@code onSuccess} as a single item or forwards any {@code onComplete} or + * {@code onError} signal. *

- * + * *

*
Scheduler:
- *
{@code fromIterable} does not operate by default on a particular {@link Scheduler}.
+ *
{@code fromMaybe} does not operate by default on a particular {@link Scheduler}.
*
- * - * @param source - * the source {@link Iterable} sequence - * @param - * the type of items in the {@link Iterable} sequence and the type of items to be emitted by the - * resulting ObservableSource - * @return an Observable that emits each item in the source {@link Iterable} sequence - * @see ReactiveX operators documentation: From - * @see #fromStream(Stream) + * @param the value type of the {@code MaybeSource} element + * @param maybe the {@code MaybeSource} instance to subscribe to, not {@code null} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code maybe} is {@code null} + * @since 3.0.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable fromIterable(@NonNull Iterable source) { - Objects.requireNonNull(source, "source is null"); - return RxJavaPlugins.onAssembly(new ObservableFromIterable<>(source)); + public static <@NonNull T> Observable fromMaybe(@NonNull MaybeSource maybe) { + Objects.requireNonNull(maybe, "maybe is null"); + return RxJavaPlugins.onAssembly(new MaybeToObservable<>(maybe)); } /** - * Converts an arbitrary Reactive-Streams Publisher into an Observable. + * Converts an arbitrary Reactive Streams {@link Publisher} into an {@code Observable}. *

* *

- * The {@link Publisher} must follow the + * The {@code Publisher} must follow the * Reactive-Streams specification. * Violating the specification may result in undefined behavior. *

* If possible, use {@link #create(ObservableOnSubscribe)} to create a * source-like {@code Observable} instead. *

- * Note that even though {@link Publisher} appears to be a functional interface, it + * Note that even though {@code Publisher} appears to be a functional interface, it * is not recommended to implement it through a lambda as the specification requires * state management that is not achievable with a stateless lambda. *

@@ -1966,45 +2148,105 @@ public static Observable fromIterable(@NonNull Iterable sour *
{@code fromPublisher} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type of the flow - * @param publisher the Publisher to convert - * @return the new Observable instance - * @throws NullPointerException if publisher is null + * @param publisher the {@code Publisher} to convert + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code publisher} is {@code null} * @see #create(ObservableOnSubscribe) */ @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable fromPublisher(@NonNull Publisher publisher) { + public static <@NonNull T> Observable fromPublisher(@NonNull Publisher publisher) { Objects.requireNonNull(publisher, "publisher is null"); return RxJavaPlugins.onAssembly(new ObservableFromPublisher<>(publisher)); } /** - * Returns an Observable that, when an observer subscribes to it, invokes a supplier function you specify and then + * Returns an {@code Observable} instance that runs the given {@link Runnable} for each {@link Observer} and + * emits either its unchecked exception or simply completes. + *

+ * + *

+ * If the code to be wrapped needs to throw a checked or more broader {@link Throwable} exception, that + * exception has to be converted to an unchecked exception by the wrapped code itself. Alternatively, + * use the {@link #fromAction(Action)} method which allows the wrapped code to throw any {@code Throwable} + * exception and will signal it to observers as-is. + *

+ *
Scheduler:
+ *
{@code fromRunnable} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If the {@code Runnable} throws an exception, the respective {@code Throwable} is + * delivered to the downstream via {@link Observer#onError(Throwable)}, + * except when the downstream has canceled the resulting {@code Observable} source. + * In this latter case, the {@code Throwable} is delivered to the global error handler via + * {@link RxJavaPlugins#onError(Throwable)} as an {@link io.reactivex.rxjava3.exceptions.UndeliverableException UndeliverableException}. + *
+ *
+ * @param the target type + * @param run the {@code Runnable} to run for each {@code Observer} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code run} is {@code null} + * @since 3.0.0 + * @see #fromAction(Action) + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Observable fromRunnable(@NonNull Runnable run) { + Objects.requireNonNull(run, "run is null"); + return RxJavaPlugins.onAssembly(new ObservableFromRunnable<>(run)); + } + + /** + * Returns an {@code Observable} instance that when subscribed to, subscribes to the {@link SingleSource} instance and + * emits {@code onSuccess} as a single item or forwards the {@code onError} signal. + *

+ * + *

+ *
Scheduler:
+ *
{@code fromSingle} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type of the {@code SingleSource} element + * @param source the {@code SingleSource} instance to subscribe to, not {@code null} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Observable fromSingle(@NonNull SingleSource source) { + Objects.requireNonNull(source, "source is null"); + return RxJavaPlugins.onAssembly(new SingleToObservable<>(source)); + } + + /** + * Returns an {@code Observable} that, when an observer subscribes to it, invokes a supplier function you specify and then * emits the value returned from that function. *

- * + * *

* This allows you to defer the execution of the function you specify until an observer subscribes to the - * ObservableSource. That is to say, it makes the function "lazy." + * {@code Observable}. That is to say, it makes the function "lazy." *

*
Scheduler:
*
{@code fromSupplier} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
*
If the {@link Supplier} throws an exception, the respective {@link Throwable} is * delivered to the downstream via {@link Observer#onError(Throwable)}, - * except when the downstream has disposed this {@code Observable} source. + * except when the downstream has disposed the current {@code Observable} source. * In this latter case, the {@code Throwable} is delivered to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} as an {@link io.reactivex.rxjava3.exceptions.UndeliverableException UndeliverableException}. + * {@link RxJavaPlugins#onError(Throwable)} as an {@link UndeliverableException}. *
*
* @param supplier * a function, the execution of which should be deferred; {@code fromSupplier} will invoke this - * function only when an observer subscribes to the ObservableSource that {@code fromSupplier} returns + * function only when an observer subscribes to the {@code Observable} that {@code fromSupplier} returns * @param - * the type of the item emitted by the ObservableSource - * @return an Observable whose {@link Observer}s' subscriptions trigger an invocation of the given function + * the type of the item emitted by the {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code supplier} is {@code null} * @see #defer(Supplier) * @see #fromCallable(Callable) * @since 3.0.0 @@ -2012,7 +2254,7 @@ public static Observable fromPublisher(@NonNull Publisher pu @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable fromSupplier(@NonNull Supplier supplier) { + public static <@NonNull T> Observable fromSupplier(@NonNull Supplier supplier) { Objects.requireNonNull(supplier, "supplier is null"); return RxJavaPlugins.onAssembly(new ObservableFromSupplier<>(supplier)); } @@ -2020,7 +2262,7 @@ public static Observable fromSupplier(@NonNull Supplier supp /** * Returns a cold, synchronous and stateless generator of values. *

- * + * *

* Note that the {@link Emitter#onNext}, {@link Emitter#onError} and * {@link Emitter#onComplete} methods provided to the function via the {@link Emitter} instance should be called synchronously, @@ -2032,16 +2274,17 @@ public static Observable fromSupplier(@NonNull Supplier supp *

* * @param the generated value type - * @param generator the Consumer called whenever a particular downstream Observer has - * requested a value. The callback then should call {@code onNext}, {@code onError} or - * {@code onComplete} to signal a value or a terminal event. Signalling multiple {@code onNext} - * in a call will make the operator signal {@code IllegalStateException}. - * @return the new Observable instance + * @param generator the {@link Consumer} called in a loop after a downstream {@link Observer} has + * subscribed. The callback then should call {@code onNext}, {@code onError} or + * {@code onComplete} to signal a value or a terminal event. Signaling multiple {@code onNext} + * in a call will make the operator signal {@link IllegalStateException}. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code generator} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable generate(@NonNull Consumer> generator) { + public static <@NonNull T> Observable generate(@NonNull Consumer> generator) { Objects.requireNonNull(generator, "generator is null"); return generate(Functions.nullSupplier(), ObservableInternalHelper.simpleGenerator(generator), Functions.emptyConsumer()); @@ -2050,7 +2293,7 @@ public static Observable generate(@NonNull Consumer> generator /** * Returns a cold, synchronous and stateful generator of values. *

- * + * *

* Note that the {@link Emitter#onNext}, {@link Emitter#onError} and * {@link Emitter#onComplete} methods provided to the function via the {@link Emitter} instance should be called synchronously, @@ -2061,19 +2304,20 @@ public static Observable generate(@NonNull Consumer> generator *

{@code generate} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the type of the per-Observer state + * @param the type of the per-{@link Observer} state * @param the generated value type - * @param initialState the Supplier to generate the initial state for each Observer - * @param generator the Consumer called with the current state whenever a particular downstream Observer has - * requested a value. The callback then should call {@code onNext}, {@code onError} or - * {@code onComplete} to signal a value or a terminal event. Signalling multiple {@code onNext} - * in a call will make the operator signal {@code IllegalStateException}. - * @return the new Observable instance + * @param initialState the {@link Supplier} to generate the initial state for each {@code Observer} + * @param generator the {@link BiConsumer} called in a loop after a downstream {@code Observer} has + * subscribed. The callback then should call {@code onNext}, {@code onError} or + * {@code onComplete} to signal a value or a terminal event. Signaling multiple {@code onNext} + * in a call will make the operator signal {@link IllegalStateException}. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code initialState} or {@code generator} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable generate(@NonNull Supplier initialState, @NonNull BiConsumer> generator) { + public static <@NonNull T, @NonNull S> Observable generate(@NonNull Supplier initialState, @NonNull BiConsumer> generator) { Objects.requireNonNull(generator, "generator is null"); return generate(initialState, ObservableInternalHelper.simpleBiGenerator(generator), Functions.emptyConsumer()); } @@ -2081,7 +2325,7 @@ public static Observable generate(@NonNull Supplier initialState, @ /** * Returns a cold, synchronous and stateful generator of values. *

- * + * *

* Note that the {@link Emitter#onNext}, {@link Emitter#onError} and * {@link Emitter#onComplete} methods provided to the function via the {@link Emitter} instance should be called synchronously, @@ -2092,21 +2336,22 @@ public static Observable generate(@NonNull Supplier initialState, @ *

{@code generate} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the type of the per-Observer state + * @param the type of the per-{@link Observer} state * @param the generated value type - * @param initialState the Supplier to generate the initial state for each Observer - * @param generator the Consumer called with the current state whenever a particular downstream Observer has - * requested a value. The callback then should call {@code onNext}, {@code onError} or - * {@code onComplete} to signal a value or a terminal event. Signalling multiple {@code onNext} - * in a call will make the operator signal {@code IllegalStateException}. - * @param disposeState the Consumer that is called with the current state when the generator + * @param initialState the {@link Supplier} to generate the initial state for each {@code Observer} + * @param generator the {@link BiConsumer} called in a loop after a downstream {@code Observer} has + * subscribed. The callback then should call {@code onNext}, {@code onError} or + * {@code onComplete} to signal a value or a terminal event. Signaling multiple {@code onNext} + * in a call will make the operator signal {@link IllegalStateException}. + * @param disposeState the {@link Consumer} that is called with the current state when the generator * terminates the sequence or it gets disposed - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code initialState}, {@code generator} or {@code disposeState} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable generate( + public static <@NonNull T, @NonNull S> Observable generate( @NonNull Supplier initialState, @NonNull BiConsumer> generator, @NonNull Consumer disposeState) { @@ -2117,7 +2362,7 @@ public static Observable generate( /** * Returns a cold, synchronous and stateful generator of values. *

- * + * *

* Note that the {@link Emitter#onNext}, {@link Emitter#onError} and * {@link Emitter#onComplete} methods provided to the function via the {@link Emitter} instance should be called synchronously, @@ -2128,27 +2373,28 @@ public static Observable generate( *

{@code generate} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the type of the per-Observer state + * @param the type of the per-{@link Observer} state * @param the generated value type - * @param initialState the Supplier to generate the initial state for each Observer - * @param generator the Function called with the current state whenever a particular downstream Observer has - * requested a value. The callback then should call {@code onNext}, {@code onError} or + * @param initialState the {@link Supplier} to generate the initial state for each {@code Observer} + * @param generator the {@link BiConsumer} called in a loop after a downstream {@code Observer} has + * subscribed. The callback then should call {@code onNext}, {@code onError} or * {@code onComplete} to signal a value or a terminal event and should return a (new) state for - * the next invocation. Signalling multiple {@code onNext} - * in a call will make the operator signal {@code IllegalStateException}. - * @return the new Observable instance + * the next invocation. Signaling multiple {@code onNext} + * in a call will make the operator signal {@link IllegalStateException}. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code initialState} or {@code generator} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable generate(@NonNull Supplier initialState, @NonNull BiFunction, S> generator) { + public static <@NonNull T, @NonNull S> Observable generate(@NonNull Supplier initialState, @NonNull BiFunction, S> generator) { return generate(initialState, generator, Functions.emptyConsumer()); } /** * Returns a cold, synchronous and stateful generator of values. *

- * + * *

* Note that the {@link Emitter#onNext}, {@link Emitter#onError} and * {@link Emitter#onComplete} methods provided to the function via the {@link Emitter} instance should be called synchronously, @@ -2159,22 +2405,23 @@ public static Observable generate(@NonNull Supplier initialState, @ *

{@code generate} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the type of the per-Observer state + * @param the type of the per-{@link Observer} state * @param the generated value type - * @param initialState the Supplier to generate the initial state for each Observer - * @param generator the Function called with the current state whenever a particular downstream Observer has - * requested a value. The callback then should call {@code onNext}, {@code onError} or + * @param initialState the {@link Supplier} to generate the initial state for each {@code Observer} + * @param generator the {@link BiConsumer} called in a loop after a downstream {@code Observer} has + * subscribed. The callback then should call {@code onNext}, {@code onError} or * {@code onComplete} to signal a value or a terminal event and should return a (new) state for - * the next invocation. Signalling multiple {@code onNext} - * in a call will make the operator signal {@code IllegalStateException}. - * @param disposeState the Consumer that is called with the current state when the generator + * the next invocation. Signaling multiple {@code onNext} + * in a call will make the operator signal {@link IllegalStateException}. + * @param disposeState the {@link Consumer} that is called with the current state when the generator * terminates the sequence or it gets disposed - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code initialState}, {@code generator} or {@code disposeState} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable generate(@NonNull Supplier initialState, @NonNull BiFunction, S> generator, + public static <@NonNull T, @NonNull S> Observable generate(@NonNull Supplier initialState, @NonNull BiFunction, S> generator, @NonNull Consumer disposeState) { Objects.requireNonNull(initialState, "initialState is null"); Objects.requireNonNull(generator, "generator is null"); @@ -2183,10 +2430,10 @@ public static Observable generate(@NonNull Supplier initialState, @ } /** - * Returns an Observable that emits a {@code 0L} after the {@code initialDelay} and ever increasing numbers + * Returns an {@code Observable} that emits a {@code 0L} after the {@code initialDelay} and ever increasing numbers * after each {@code period} of time thereafter. *

- * + * *

*
Scheduler:
*
{@code interval} operates by default on the {@code computation} {@link Scheduler}.
@@ -2198,9 +2445,9 @@ public static Observable generate(@NonNull Supplier initialState, @ * the period of time between emissions of the subsequent numbers * @param unit * the time unit for both {@code initialDelay} and {@code period} - * @return an Observable that emits a 0L after the {@code initialDelay} and ever increasing numbers after - * each {@code period} of time thereafter + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Interval + * @throws NullPointerException if {@code unit} is {@code null} * @since 1.0.12 */ @CheckReturnValue @@ -2211,13 +2458,13 @@ public static Observable interval(long initialDelay, long period, @NonNull } /** - * Returns an Observable that emits a {@code 0L} after the {@code initialDelay} and ever increasing numbers + * Returns an {@code Observable} that emits a {@code 0L} after the {@code initialDelay} and ever increasing numbers * after each {@code period} of time thereafter, on a specified {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param initialDelay @@ -2227,11 +2474,11 @@ public static Observable interval(long initialDelay, long period, @NonNull * @param unit * the time unit for both {@code initialDelay} and {@code period} * @param scheduler - * the Scheduler on which the waiting happens and items are emitted - * @return an Observable that emits a 0L after the {@code initialDelay} and ever increasing numbers after - * each {@code period} of time thereafter, while running on the given Scheduler + * the {@code Scheduler} on which the waiting happens and items are emitted + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Interval * @since 1.0.12 + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} */ @CheckReturnValue @NonNull @@ -2244,9 +2491,9 @@ public static Observable interval(long initialDelay, long period, @NonNull } /** - * Returns an Observable that emits a sequential number every specified interval of time. + * Returns an {@code Observable} that emits a sequential number every specified interval of time. *

- * + * *

*
Scheduler:
*
{@code interval} operates by default on the {@code computation} {@link Scheduler}.
@@ -2256,7 +2503,8 @@ public static Observable interval(long initialDelay, long period, @NonNull * the period size in time units (see below) * @param unit * time units to use for the interval size - * @return an Observable that emits a sequential number each time interval + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Interval */ @CheckReturnValue @@ -2267,13 +2515,13 @@ public static Observable interval(long period, @NonNull TimeUnit unit) { } /** - * Returns an Observable that emits a sequential number every specified interval of time, on a - * specified Scheduler. + * Returns an {@code Observable} that emits a sequential number every specified interval of time, on a + * specified {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param period @@ -2281,8 +2529,9 @@ public static Observable interval(long period, @NonNull TimeUnit unit) { * @param unit * time units to use for the interval size * @param scheduler - * the Scheduler to use for scheduling the items - * @return an Observable that emits a sequential number each time interval + * the {@code Scheduler} to use for scheduling the items + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Interval */ @CheckReturnValue @@ -2297,21 +2546,26 @@ public static Observable interval(long period, @NonNull TimeUnit unit, @No *

* The sequence completes immediately after the last value (start + count - 1) has been reached. *

- * + * *

*
Scheduler:
*
{@code intervalRange} by default operates on the {@link Schedulers#computation() computation} {@link Scheduler}.
*
* @param start that start value of the range - * @param count the number of values to emit in total, if zero, the operator emits an onComplete after the initial delay. - * @param initialDelay the initial delay before signalling the first value (the start) + * @param count the number of values to emit in total, if zero, the operator emits an {@code onComplete} after the initial delay. + * @param initialDelay the initial delay before signaling the first value (the start) * @param period the period between subsequent values - * @param unit the unit of measure of the initialDelay and period amounts - * @return the new Observable instance + * @param unit the unit of measure of the {@code initialDelay} and {@code period} amounts + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException + * if {@code count} is negative, or if {@code start} + {@code count} − 1 exceeds + * {@link Long#MAX_VALUE} + * @see #range(int, int) */ @CheckReturnValue - @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull + @SchedulerSupport(SchedulerSupport.COMPUTATION) public static Observable intervalRange(long start, long count, long initialDelay, long period, @NonNull TimeUnit unit) { return intervalRange(start, count, initialDelay, period, unit, Schedulers.computation()); } @@ -2321,17 +2575,21 @@ public static Observable intervalRange(long start, long count, long initia *

* The sequence completes immediately after the last value (start + count - 1) has been reached. *

- * *

+ * *
*
Scheduler:
*
you provide the {@link Scheduler}.
*
* @param start that start value of the range - * @param count the number of values to emit in total, if zero, the operator emits an onComplete after the initial delay. - * @param initialDelay the initial delay before signalling the first value (the start) + * @param count the number of values to emit in total, if zero, the operator emits an {@code onComplete} after the initial delay. + * @param initialDelay the initial delay before signaling the first value (the start) * @param period the period between subsequent values - * @param unit the unit of measure of the initialDelay and period amounts + * @param unit the unit of measure of the {@code initialDelay} and {@code period} amounts * @param scheduler the target scheduler where the values and terminal signals will be emitted - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException + * if {@code count} is negative, or if {@code start} + {@code count} − 1 exceeds + * {@link Long#MAX_VALUE} */ @CheckReturnValue @NonNull @@ -2356,12 +2614,12 @@ public static Observable intervalRange(long start, long count, long initia } /** - * Returns an Observable that signals the given (constant reference) item and then completes. + * Returns an {@code Observable} that signals the given (constant reference) item and then completes. *

* *

* Note that the item is taken and re-emitted as is and not computed by any means by {@code just}. Use {@link #fromCallable(Callable)} - * to generate a single item on demand (when {@code Observer}s subscribe to it). + * to generate a single item on demand (when {@link Observer}s subscribe to it). *

* See the multi-parameter overloads of {@code just} to emit more than one (constant reference) items one after the other. * Use {@link #fromArray(Object...)} to emit an arbitrary number of items that are known upfront. @@ -2376,7 +2634,8 @@ public static Observable intervalRange(long start, long count, long initia * the item to emit * @param * the type of that item - * @return an Observable that emits {@code value} as a single item and then completes + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code item} is {@code null} * @see ReactiveX operators documentation: Just * @see #just(Object, Object) * @see #fromCallable(Callable) @@ -2386,15 +2645,15 @@ public static Observable intervalRange(long start, long count, long initia @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable just(@NonNull T item) { + public static <@NonNull T> Observable just(@NonNull T item) { Objects.requireNonNull(item, "item is null"); return RxJavaPlugins.onAssembly(new ObservableJust<>(item)); } /** - * Converts two items into an ObservableSource that emits those items. + * Converts two items into an {@code Observable} that emits those items. *

- * + * *

*
Scheduler:
*
{@code just} does not operate by default on a particular {@link Scheduler}.
@@ -2406,13 +2665,14 @@ public static Observable just(@NonNull T item) { * second item * @param * the type of these items - * @return an Observable that emits each item + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code item1} or {@code item2} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable just(@NonNull T item1, @NonNull T item2) { + public static <@NonNull T> Observable just(@NonNull T item1, @NonNull T item2) { Objects.requireNonNull(item1, "item1 is null"); Objects.requireNonNull(item2, "item2 is null"); @@ -2420,9 +2680,9 @@ public static Observable just(@NonNull T item1, @NonNull T item2) { } /** - * Converts three items into an ObservableSource that emits those items. + * Converts three items into an {@code Observable} that emits those items. *

- * + * *

*
Scheduler:
*
{@code just} does not operate by default on a particular {@link Scheduler}.
@@ -2436,13 +2696,14 @@ public static Observable just(@NonNull T item1, @NonNull T item2) { * third item * @param * the type of these items - * @return an Observable that emits each item + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code item1}, {@code item2} or {@code item3} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3) { + public static <@NonNull T> Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3) { Objects.requireNonNull(item1, "item1 is null"); Objects.requireNonNull(item2, "item2 is null"); Objects.requireNonNull(item3, "item3 is null"); @@ -2451,9 +2712,9 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul } /** - * Converts four items into an ObservableSource that emits those items. + * Converts four items into an {@code Observable} that emits those items. *

- * + * *

*
Scheduler:
*
{@code just} does not operate by default on a particular {@link Scheduler}.
@@ -2469,13 +2730,14 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul * fourth item * @param * the type of these items - * @return an Observable that emits each item + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3} or {@code item4} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4) { + public static <@NonNull T> Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4) { Objects.requireNonNull(item1, "item1 is null"); Objects.requireNonNull(item2, "item2 is null"); Objects.requireNonNull(item3, "item3 is null"); @@ -2485,9 +2747,9 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul } /** - * Converts five items into an ObservableSource that emits those items. + * Converts five items into an {@code Observable} that emits those items. *

- * + * *

*
Scheduler:
*
{@code just} does not operate by default on a particular {@link Scheduler}.
@@ -2505,13 +2767,15 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul * fifth item * @param * the type of these items - * @return an Observable that emits each item + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3}, + * {@code item4} or {@code item5} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4, @NonNull T item5) { + public static <@NonNull T> Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4, @NonNull T item5) { Objects.requireNonNull(item1, "item1 is null"); Objects.requireNonNull(item2, "item2 is null"); Objects.requireNonNull(item3, "item3 is null"); @@ -2522,9 +2786,9 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul } /** - * Converts six items into an ObservableSource that emits those items. + * Converts six items into an {@code Observable} that emits those items. *

- * + * *

*
Scheduler:
*
{@code just} does not operate by default on a particular {@link Scheduler}.
@@ -2544,13 +2808,15 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul * sixth item * @param * the type of these items - * @return an Observable that emits each item + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3}, + * {@code item4}, {@code item5} or {@code item6} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4, @NonNull T item5, @NonNull T item6) { + public static <@NonNull T> Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4, @NonNull T item5, @NonNull T item6) { Objects.requireNonNull(item1, "item1 is null"); Objects.requireNonNull(item2, "item2 is null"); Objects.requireNonNull(item3, "item3 is null"); @@ -2562,9 +2828,9 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul } /** - * Converts seven items into an ObservableSource that emits those items. + * Converts seven items into an {@code Observable} that emits those items. *

- * + * *

*
Scheduler:
*
{@code just} does not operate by default on a particular {@link Scheduler}.
@@ -2586,13 +2852,16 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul * seventh item * @param * the type of these items - * @return an Observable that emits each item + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3}, + * {@code item4}, {@code item5}, {@code item6} + * or {@code item7} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4, @NonNull T item5, @NonNull T item6, @NonNull T item7) { + public static <@NonNull T> Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4, @NonNull T item5, @NonNull T item6, @NonNull T item7) { Objects.requireNonNull(item1, "item1 is null"); Objects.requireNonNull(item2, "item2 is null"); Objects.requireNonNull(item3, "item3 is null"); @@ -2605,9 +2874,9 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul } /** - * Converts eight items into an ObservableSource that emits those items. + * Converts eight items into an {@code Observable} that emits those items. *

- * + * *

*
Scheduler:
*
{@code just} does not operate by default on a particular {@link Scheduler}.
@@ -2631,13 +2900,16 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul * eighth item * @param * the type of these items - * @return an Observable that emits each item + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3}, + * {@code item4}, {@code item5}, {@code item6} + * {@code item7} or {@code item8} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4, @NonNull T item5, @NonNull T item6, @NonNull T item7, @NonNull T item8) { + public static <@NonNull T> Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4, @NonNull T item5, @NonNull T item6, @NonNull T item7, @NonNull T item8) { Objects.requireNonNull(item1, "item1 is null"); Objects.requireNonNull(item2, "item2 is null"); Objects.requireNonNull(item3, "item3 is null"); @@ -2651,9 +2923,9 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul } /** - * Converts nine items into an ObservableSource that emits those items. + * Converts nine items into an {@code Observable} that emits those items. *

- * + * *

*
Scheduler:
*
{@code just} does not operate by default on a particular {@link Scheduler}.
@@ -2679,13 +2951,16 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul * ninth item * @param * the type of these items - * @return an Observable that emits each item + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3}, + * {@code item4}, {@code item5}, {@code item6} + * {@code item7}, {@code item8} or {@code item9} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4, @NonNull T item5, @NonNull T item6, @NonNull T item7, @NonNull T item8, @NonNull T item9) { + public static <@NonNull T> Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4, @NonNull T item5, @NonNull T item6, @NonNull T item7, @NonNull T item8, @NonNull T item9) { Objects.requireNonNull(item1, "item1 is null"); Objects.requireNonNull(item2, "item2 is null"); Objects.requireNonNull(item3, "item3 is null"); @@ -2700,9 +2975,9 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul } /** - * Converts ten items into an ObservableSource that emits those items. + * Converts ten items into an {@code Observable} that emits those items. *

- * + * *

*
Scheduler:
*
{@code just} does not operate by default on a particular {@link Scheduler}.
@@ -2730,13 +3005,17 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul * tenth item * @param * the type of these items - * @return an Observable that emits each item + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code item1}, {@code item2}, {@code item3}, + * {@code item4}, {@code item5}, {@code item6} + * {@code item7}, {@code item8}, {@code item9} + * or {@code item10} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4, @NonNull T item5, @NonNull T item6, @NonNull T item7, @NonNull T item8, @NonNull T item9, @NonNull T item10) { + public static <@NonNull T> Observable just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4, @NonNull T item5, @NonNull T item6, @NonNull T item7, @NonNull T item8, @NonNull T item9, @NonNull T item10) { Objects.requireNonNull(item1, "item1 is null"); Objects.requireNonNull(item2, "item2 is null"); Objects.requireNonNull(item3, "item3 is null"); @@ -2752,24 +3031,24 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul } /** - * Flattens an Iterable of ObservableSources into one ObservableSource, without any transformation, while limiting the - * number of concurrent subscriptions to these ObservableSources. + * Flattens an {@link Iterable} of {@link ObservableSource}s into one {@code Observable}, without any transformation, while limiting the + * number of concurrent subscriptions to these {@code ObservableSource}s. *

- * + * *

- * You can combine the items emitted by multiple ObservableSources so that they appear as a single ObservableSource, by + * You can combine the items emitted by multiple {@code ObservableSource}s so that they appear as a single {@code ObservableSource}, by * using the {@code merge} method. *

*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code ObservableSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the returned {@code ObservableSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Observable} terminates with that {@code Throwable} and all other source {@code ObservableSource}s are disposed. * If more than one {@code ObservableSource} signals an error, the resulting {@code Observable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Observable} has been disposed or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(Iterable, int, int)} to merge sources and terminate only when all source {@code ObservableSource}s @@ -2779,15 +3058,15 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul * * @param the common element base type * @param sources - * the Iterable of ObservableSources + * the {@code Iterable} of {@code ObservableSource}s * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently * @param bufferSize - * the number of items to prefetch from each inner ObservableSource - * @return an Observable that emits items that are the result of flattening the items emitted by the - * ObservableSources in the Iterable + * the number of items expected from each inner {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @throws IllegalArgumentException - * if {@code maxConcurrent} is less than or equal to 0 + * if {@code maxConcurrency} or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(Iterable, int, int) */ @@ -2795,29 +3074,29 @@ public static Observable just(@NonNull T item1, @NonNull T item2, @NonNul @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable merge(@NonNull Iterable> sources, int maxConcurrency, int bufferSize) { + public static <@NonNull T> Observable merge(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, int maxConcurrency, int bufferSize) { return fromIterable(sources).flatMap((Function)Functions.identity(), false, maxConcurrency, bufferSize); } /** - * Flattens an Iterable of ObservableSources into one ObservableSource, without any transformation, while limiting the - * number of concurrent subscriptions to these ObservableSources. + * Flattens an array of {@link ObservableSource}s into one {@code Observable}, without any transformation, while limiting the + * number of concurrent subscriptions to these {@code ObservableSource}s. *

- * + * *

- * You can combine the items emitted by multiple ObservableSources so that they appear as a single ObservableSource, by + * You can combine the items emitted by multiple {@code ObservableSource}s so that they appear as a single {@code ObservableSource}, by * using the {@code merge} method. *

*
Scheduler:
*
{@code mergeArray} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code ObservableSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the {@code ObservableSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Observable} terminates with that {@code Throwable} and all other source {@code ObservableSource}s are disposed. * If more than one {@code ObservableSource} signals an error, the resulting {@code Observable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Observable} has been disposed or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeArrayDelayError(int, int, ObservableSource...)} to merge sources and terminate only when all source {@code ObservableSource}s @@ -2827,15 +3106,15 @@ public static Observable merge(@NonNull Iterable the common element base type * @param sources - * the array of ObservableSources + * the array of {@code ObservableSource}s * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently * @param bufferSize - * the number of items to prefetch from each inner ObservableSource - * @return an Observable that emits items that are the result of flattening the items emitted by the - * ObservableSources in the Iterable + * the number of items expected from each inner {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @throws IllegalArgumentException - * if {@code maxConcurrent} is less than or equal to 0 + * if {@code maxConcurrency} or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Merge * @see #mergeArrayDelayError(int, int, ObservableSource...) */ @@ -2844,28 +3123,28 @@ public static Observable merge(@NonNull Iterable Observable mergeArray(int maxConcurrency, int bufferSize, @NonNull ObservableSource... sources) { + public static <@NonNull T> Observable mergeArray(int maxConcurrency, int bufferSize, @NonNull ObservableSource... sources) { return fromArray(sources).flatMap((Function)Functions.identity(), false, maxConcurrency, bufferSize); } /** - * Flattens an Iterable of ObservableSources into one ObservableSource, without any transformation. + * Flattens an {@link Iterable} of {@link ObservableSource}s into one {@code Observable}, without any transformation. *

- * + * *

- * You can combine the items emitted by multiple ObservableSources so that they appear as a single ObservableSource, by + * You can combine the items emitted by multiple {@code ObservableSource}s so that they appear as a single {@code ObservableSource}, by * using the {@code merge} method. *

*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code ObservableSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the returned {@code ObservableSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Observable} terminates with that {@code Throwable} and all other source {@code ObservableSource}s are disposed. * If more than one {@code ObservableSource} signals an error, the resulting {@code Observable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Observable} has been disposed or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(Iterable)} to merge sources and terminate only when all source {@code ObservableSource}s @@ -2875,9 +3154,9 @@ public static Observable mergeArray(int maxConcurrency, int bufferSize, @ * * @param the common element base type * @param sources - * the Iterable of ObservableSources - * @return an Observable that emits items that are the result of flattening the items emitted by the - * ObservableSources in the Iterable + * the {@code Iterable} of {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(Iterable) */ @@ -2885,29 +3164,29 @@ public static Observable mergeArray(int maxConcurrency, int bufferSize, @ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable merge(@NonNull Iterable> sources) { + public static <@NonNull T> Observable merge(@NonNull Iterable<@NonNull ? extends ObservableSource> sources) { return fromIterable(sources).flatMap((Function)Functions.identity()); } /** - * Flattens an Iterable of ObservableSources into one ObservableSource, without any transformation, while limiting the - * number of concurrent subscriptions to these ObservableSources. + * Flattens an {@link Iterable} of {@link ObservableSource}s into one {@code Observable}, without any transformation, while limiting the + * number of concurrent subscriptions to these {@code ObservableSource}s. *

- * + * *

- * You can combine the items emitted by multiple ObservableSources so that they appear as a single ObservableSource, by + * You can combine the items emitted by multiple {@code ObservableSource}s so that they appear as a single {@code ObservableSource}, by * using the {@code merge} method. *

*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code ObservableSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the returned {@code ObservableSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Observable} terminates with that {@code Throwable} and all other source {@code ObservableSource}s are disposed. * If more than one {@code ObservableSource} signals an error, the resulting {@code Observable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Observable} has been disposed or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(Iterable, int)} to merge sources and terminate only when all source {@code ObservableSource}s @@ -2917,13 +3196,13 @@ public static Observable merge(@NonNull Iterable the common element base type * @param sources - * the Iterable of ObservableSources + * the {@code Iterable} of {@code ObservableSource}s * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently - * @return an Observable that emits items that are the result of flattening the items emitted by the - * ObservableSources in the Iterable + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @throws IllegalArgumentException - * if {@code maxConcurrent} is less than or equal to 0 + * if {@code maxConcurrency} is less than or equal to 0 * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(Iterable, int) */ @@ -2931,29 +3210,29 @@ public static Observable merge(@NonNull Iterable Observable merge(@NonNull Iterable> sources, int maxConcurrency) { + public static <@NonNull T> Observable merge(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, int maxConcurrency) { return fromIterable(sources).flatMap((Function)Functions.identity(), maxConcurrency); } /** - * Flattens an ObservableSource that emits ObservableSources into a single ObservableSource that emits the items emitted by - * those ObservableSources, without any transformation. + * Flattens an {@link ObservableSource} that emits {@code ObservableSource}s into a single {@code Observable} that emits the items emitted by + * those {@code ObservableSource}s, without any transformation. *

- * + * *

- * You can combine the items emitted by multiple ObservableSources so that they appear as a single ObservableSource, by + * You can combine the items emitted by multiple {@code ObservableSource}s so that they appear as a single {@code ObservableSource}, by * using the {@code merge} method. *

*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code ObservableSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the returned {@code ObservableSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Observable} terminates with that {@code Throwable} and all other source {@code ObservableSource}s are disposed. * If more than one {@code ObservableSource} signals an error, the resulting {@code Observable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Observable} has been disposed or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(ObservableSource)} to merge sources and terminate only when all source {@code ObservableSource}s @@ -2963,41 +3242,41 @@ public static Observable merge(@NonNull Iterable the common element base type * @param sources - * an ObservableSource that emits ObservableSources - * @return an Observable that emits items that are the result of flattening the ObservableSources emitted by the - * {@code source} ObservableSource + * an {@code ObservableSource} that emits {@code ObservableSource}s + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Merge + * @throws NullPointerException if {@code sources} is {@code null} * @see #mergeDelayError(ObservableSource) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @SuppressWarnings({ "unchecked", "rawtypes" }) @NonNull - public static Observable merge(@NonNull ObservableSource> sources) { + public static <@NonNull T> Observable merge(@NonNull ObservableSource> sources) { Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new ObservableFlatMap(sources, Functions.identity(), false, Integer.MAX_VALUE, bufferSize())); } /** - * Flattens an ObservableSource that emits ObservableSources into a single ObservableSource that emits the items emitted by - * those ObservableSources, without any transformation, while limiting the maximum number of concurrent - * subscriptions to these ObservableSources. + * Flattens an {@link ObservableSource} that emits {@code ObservableSource}s into a single {@code Observable} that emits the items emitted by + * those {@code ObservableSource}s, without any transformation, while limiting the maximum number of concurrent + * subscriptions to these {@code ObservableSource}s. *

- * + * *

- * You can combine the items emitted by multiple ObservableSources so that they appear as a single ObservableSource, by + * You can combine the items emitted by multiple {@code ObservableSource}s so that they appear as a single {@code ObservableSource}, by * using the {@code merge} method. *

*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code ObservableSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the returned {@code ObservableSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Observable} terminates with that {@code Throwable} and all other source {@code ObservableSource}s are disposed. * If more than one {@code ObservableSource} signals an error, the resulting {@code Observable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Observable} has been disposed or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(ObservableSource, int)} to merge sources and terminate only when all source {@code ObservableSource}s @@ -3007,13 +3286,13 @@ public static Observable merge(@NonNull ObservableSource the common element base type * @param sources - * an ObservableSource that emits ObservableSources + * an {@code ObservableSource} that emits {@code ObservableSource}s * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently - * @return an Observable that emits items that are the result of flattening the ObservableSources emitted by the - * {@code source} ObservableSource + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @throws IllegalArgumentException - * if {@code maxConcurrent} is less than or equal to 0 + * if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: Merge * @since 1.1.0 * @see #mergeDelayError(ObservableSource, int) @@ -3022,30 +3301,30 @@ public static Observable merge(@NonNull ObservableSource Observable merge(@NonNull ObservableSource> sources, int maxConcurrency) { + public static <@NonNull T> Observable merge(@NonNull ObservableSource> sources, int maxConcurrency) { Objects.requireNonNull(sources, "sources is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); return RxJavaPlugins.onAssembly(new ObservableFlatMap(sources, Functions.identity(), false, maxConcurrency, bufferSize())); } /** - * Flattens two ObservableSources into a single ObservableSource, without any transformation. + * Flattens two {@link ObservableSource}s into a single {@code Observable}, without any transformation. *

- * + * *

- * You can combine items emitted by multiple ObservableSources so that they appear as a single ObservableSource, by + * You can combine items emitted by multiple {@code ObservableSource}s so that they appear as a single {@code ObservableSource}, by * using the {@code merge} method. *

*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code ObservableSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the {@code ObservableSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Observable} terminates with that {@code Throwable} and all other source {@code ObservableSource}s are disposed. * If more than one {@code ObservableSource} signals an error, the resulting {@code Observable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Observable} has been disposed or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(ObservableSource, ObservableSource)} to merge sources and terminate only when all source {@code ObservableSource}s @@ -3055,10 +3334,11 @@ public static Observable merge(@NonNull ObservableSource the common element base type * @param source1 - * an ObservableSource to be merged + * an {@code ObservableSource} to be merged * @param source2 - * an ObservableSource to be merged - * @return an Observable that emits all of the items emitted by the source ObservableSources + * an {@code ObservableSource} to be merged + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(ObservableSource, ObservableSource) */ @@ -3066,30 +3346,30 @@ public static Observable merge(@NonNull ObservableSource Observable merge(@NonNull ObservableSource source1, @NonNull ObservableSource source2) { + public static <@NonNull T> Observable merge(@NonNull ObservableSource source1, @NonNull ObservableSource source2) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); return fromArray(source1, source2).flatMap((Function)Functions.identity(), false, 2); } /** - * Flattens three ObservableSources into a single ObservableSource, without any transformation. + * Flattens three {@link ObservableSource}s into a single {@code Observable}, without any transformation. *

- * + * *

- * You can combine items emitted by multiple ObservableSources so that they appear as a single ObservableSource, by + * You can combine items emitted by multiple {@code ObservableSource}s so that they appear as a single {@code ObservableSource}, by * using the {@code merge} method. *

*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code ObservableSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the {@code ObservableSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Observable} terminates with that {@code Throwable} and all other source {@code ObservableSource}s are disposed. * If more than one {@code ObservableSource} signals an error, the resulting {@code Observable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Observable} has been disposed or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(ObservableSource, ObservableSource, ObservableSource)} to merge sources and terminate only when all source {@code ObservableSource}s @@ -3099,12 +3379,13 @@ public static Observable merge(@NonNull ObservableSource sou * * @param the common element base type * @param source1 - * an ObservableSource to be merged + * an {@code ObservableSource} to be merged * @param source2 - * an ObservableSource to be merged + * an {@code ObservableSource} to be merged * @param source3 - * an ObservableSource to be merged - * @return an Observable that emits all of the items emitted by the source ObservableSources + * an {@code ObservableSource} to be merged + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(ObservableSource, ObservableSource, ObservableSource) */ @@ -3112,7 +3393,7 @@ public static Observable merge(@NonNull ObservableSource sou @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable merge( + public static <@NonNull T> Observable merge( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3) { Objects.requireNonNull(source1, "source1 is null"); @@ -3122,23 +3403,23 @@ public static Observable merge( } /** - * Flattens four ObservableSources into a single ObservableSource, without any transformation. + * Flattens four {@link ObservableSource}s into a single {@code Observable}, without any transformation. *

- * + * *

- * You can combine items emitted by multiple ObservableSources so that they appear as a single ObservableSource, by + * You can combine items emitted by multiple {@code ObservableSource}s so that they appear as a single {@code ObservableSource}, by * using the {@code merge} method. *

*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code ObservableSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the {@code ObservableSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Observable} terminates with that {@code Throwable} and all other source {@code ObservableSource}s are disposed. * If more than one {@code ObservableSource} signals an error, the resulting {@code Observable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Observable} has been disposed or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(ObservableSource, ObservableSource, ObservableSource, ObservableSource)} to merge sources and terminate only when all source {@code ObservableSource}s @@ -3148,14 +3429,15 @@ public static Observable merge( * * @param the common element base type * @param source1 - * an ObservableSource to be merged + * an {@code ObservableSource} to be merged * @param source2 - * an ObservableSource to be merged + * an {@code ObservableSource} to be merged * @param source3 - * an ObservableSource to be merged + * an {@code ObservableSource} to be merged * @param source4 - * an ObservableSource to be merged - * @return an Observable that emits all of the items emitted by the source ObservableSources + * an {@code ObservableSource} to be merged + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(ObservableSource, ObservableSource, ObservableSource, ObservableSource) */ @@ -3163,7 +3445,7 @@ public static Observable merge( @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable merge( + public static <@NonNull T> Observable merge( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4) { Objects.requireNonNull(source1, "source1 is null"); @@ -3174,23 +3456,23 @@ public static Observable merge( } /** - * Flattens an Array of ObservableSources into one ObservableSource, without any transformation. + * Flattens an array of {@link ObservableSource}s into one {@code Observable}, without any transformation. *

- * + * *

- * You can combine items emitted by multiple ObservableSources so that they appear as a single ObservableSource, by + * You can combine items emitted by multiple {@code ObservableSource}s so that they appear as a single {@code ObservableSource}, by * using the {@code merge} method. *

*
Scheduler:
*
{@code mergeArray} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code ObservableSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the {@code ObservableSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Observable} terminates with that {@code Throwable} and all other source {@code ObservableSource}s are disposed. * If more than one {@code ObservableSource} signals an error, the resulting {@code Observable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Observable} has been disposed or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeArrayDelayError(ObservableSource...)} to merge sources and terminate only when all source {@code ObservableSource}s @@ -3200,8 +3482,9 @@ public static Observable merge( * * @param the common element base type * @param sources - * the array of ObservableSources - * @return an Observable that emits all of the items emitted by the ObservableSources in the Array + * the array of {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeArrayDelayError(ObservableSource...) */ @@ -3210,23 +3493,23 @@ public static Observable merge( @SchedulerSupport(SchedulerSupport.NONE) @NonNull @SafeVarargs - public static Observable mergeArray(@NonNull ObservableSource... sources) { + public static <@NonNull T> Observable mergeArray(@NonNull ObservableSource... sources) { return fromArray(sources).flatMap((Function)Functions.identity(), sources.length); } /** - * Flattens an Iterable of ObservableSources into one ObservableSource, in a way that allows an Observer to receive all - * successfully emitted items from each of the source ObservableSources without being interrupted by an error + * Flattens an {@link Iterable} of {@link ObservableSource}s into one {@code Observable}, in a way that allows an {@link Observer} to receive all + * successfully emitted items from each of the returned {@code ObservableSource}s without being interrupted by an error * notification from one of them. *

- * This behaves like {@link #merge(ObservableSource)} except that if any of the merged ObservableSources notify of an + * This behaves like {@link #merge(ObservableSource)} except that if any of the merged {@code ObservableSource}s notify of an * error via {@link Observer#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged ObservableSources have finished emitting items. + * error notification until all of the merged {@code ObservableSource}s have finished emitting items. *

- * + * *

- * Even if multiple merged ObservableSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Observers once. + * Even if multiple merged {@code ObservableSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its {@code Observer}s once. *

*
Scheduler:
*
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -3234,32 +3517,32 @@ public static Observable mergeArray(@NonNull ObservableSource the common element base type * @param sources - * the Iterable of ObservableSources - * @return an Observable that emits items that are the result of flattening the items emitted by the - * ObservableSources in the Iterable + * the {@code Iterable} of {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable mergeDelayError(@NonNull Iterable> sources) { + public static <@NonNull T> Observable mergeDelayError(@NonNull Iterable<@NonNull ? extends ObservableSource> sources) { return fromIterable(sources).flatMap((Function)Functions.identity(), true); } /** - * Flattens an Iterable of ObservableSources into one ObservableSource, in a way that allows an Observer to receive all - * successfully emitted items from each of the source ObservableSources without being interrupted by an error - * notification from one of them, while limiting the number of concurrent subscriptions to these ObservableSources. + * Flattens an {@link Iterable} of {@link ObservableSource}s into one {@code Observable}, in a way that allows an {@link Observer} to receive all + * successfully emitted items from each of the returned {@code ObservableSource}s without being interrupted by an error + * notification from one of them, while limiting the number of concurrent subscriptions to these {@code ObservableSource}s. *

- * This behaves like {@link #merge(ObservableSource)} except that if any of the merged ObservableSources notify of an + * This behaves like {@link #merge(ObservableSource)} except that if any of the merged {@code ObservableSource}s notify of an * error via {@link Observer#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged ObservableSources have finished emitting items. + * error notification until all of the merged {@code ObservableSource}s have finished emitting items. *

- * + * *

- * Even if multiple merged ObservableSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Observers once. + * Even if multiple merged {@code ObservableSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its {@code Observer}s once. *

*
Scheduler:
*
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -3267,36 +3550,37 @@ public static Observable mergeDelayError(@NonNull Iterable the common element base type * @param sources - * the Iterable of ObservableSources + * the {@code Iterable} of {@code ObservableSource}s * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently * @param bufferSize - * the number of items to prefetch from each inner ObservableSource - * @return an Observable that emits items that are the result of flattening the items emitted by the - * ObservableSources in the Iterable + * the number of items expected from each inner {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable mergeDelayError(@NonNull Iterable> sources, int maxConcurrency, int bufferSize) { + public static <@NonNull T> Observable mergeDelayError(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, int maxConcurrency, int bufferSize) { return fromIterable(sources).flatMap((Function)Functions.identity(), true, maxConcurrency, bufferSize); } /** - * Flattens an array of ObservableSources into one ObservableSource, in a way that allows an Observer to receive all - * successfully emitted items from each of the source ObservableSources without being interrupted by an error - * notification from one of them, while limiting the number of concurrent subscriptions to these ObservableSources. + * Flattens an array of {@link ObservableSource}s into one {@code Observable}, in a way that allows an {@link Observer} to receive all + * successfully emitted items from each of the {@code ObservableSource}s without being interrupted by an error + * notification from one of them, while limiting the number of concurrent subscriptions to these {@code ObservableSource}s. *

- * This behaves like {@link #merge(ObservableSource)} except that if any of the merged ObservableSources notify of an + * This behaves like {@link #merge(ObservableSource)} except that if any of the merged {@code ObservableSource}s notify of an * error via {@link Observer#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged ObservableSources have finished emitting items. + * error notification until all of the merged {@code ObservableSource}s have finished emitting items. *

- * + * *

- * Even if multiple merged ObservableSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Observers once. + * Even if multiple merged {@code ObservableSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its {@code Observer}s once. *

*
Scheduler:
*
{@code mergeArrayDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -3304,13 +3588,14 @@ public static Observable mergeDelayError(@NonNull Iterable the common element base type * @param sources - * the array of ObservableSources + * the array of {@code ObservableSource}s * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently * @param bufferSize - * the number of items to prefetch from each inner ObservableSource - * @return an Observable that emits items that are the result of flattening the items emitted by the - * ObservableSources in the Iterable + * the number of items expected from each inner {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -3318,23 +3603,23 @@ public static Observable mergeDelayError(@NonNull Iterable Observable mergeArrayDelayError(int maxConcurrency, int bufferSize, @NonNull ObservableSource... sources) { + public static <@NonNull T> Observable mergeArrayDelayError(int maxConcurrency, int bufferSize, @NonNull ObservableSource... sources) { return fromArray(sources).flatMap((Function)Functions.identity(), true, maxConcurrency, bufferSize); } /** - * Flattens an Iterable of ObservableSources into one ObservableSource, in a way that allows an Observer to receive all - * successfully emitted items from each of the source ObservableSources without being interrupted by an error - * notification from one of them, while limiting the number of concurrent subscriptions to these ObservableSources. + * Flattens an {@link Iterable} of {@link ObservableSource}s into one {@code Observable}, in a way that allows an {@link Observer} to receive all + * successfully emitted items from each of the returned {@code ObservableSource}s without being interrupted by an error + * notification from one of them, while limiting the number of concurrent subscriptions to these {@code ObservableSource}s. *

- * This behaves like {@link #merge(ObservableSource)} except that if any of the merged ObservableSources notify of an + * This behaves like {@link #merge(ObservableSource)} except that if any of the merged {@code ObservableSource}s notify of an * error via {@link Observer#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged ObservableSources have finished emitting items. + * error notification until all of the merged {@code ObservableSource}s have finished emitting items. *

- * + * *

- * Even if multiple merged ObservableSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Observers once. + * Even if multiple merged {@code ObservableSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its {@code Observer}s once. *

*
Scheduler:
*
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -3342,34 +3627,35 @@ public static Observable mergeArrayDelayError(int maxConcurrency, int buf * * @param the common element base type * @param sources - * the Iterable of ObservableSources + * the {@code Iterable} of {@code ObservableSource}s * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently - * @return an Observable that emits items that are the result of flattening the items emitted by the - * ObservableSources in the Iterable + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable mergeDelayError(@NonNull Iterable> sources, int maxConcurrency) { + public static <@NonNull T> Observable mergeDelayError(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, int maxConcurrency) { return fromIterable(sources).flatMap((Function)Functions.identity(), true, maxConcurrency); } /** - * Flattens an ObservableSource that emits ObservableSources into one ObservableSource, in a way that allows an Observer to - * receive all successfully emitted items from all of the source ObservableSources without being interrupted by + * Flattens an {@link ObservableSource} that emits {@code ObservableSource}s into one {@code Observable}, in a way that allows an {@link Observer} to + * receive all successfully emitted items from all of the emitted {@code ObservableSource}s without being interrupted by * an error notification from one of them. *

- * This behaves like {@link #merge(ObservableSource)} except that if any of the merged ObservableSources notify of an + * This behaves like {@link #merge(ObservableSource)} except that if any of the merged {@code ObservableSource}s notify of an * error via {@link Observer#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged ObservableSources have finished emitting items. + * error notification until all of the merged {@code ObservableSource}s have finished emitting items. *

- * + * *

- * Even if multiple merged ObservableSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Observers once. + * Even if multiple merged {@code ObservableSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its {@code Observer}s once. *

*
Scheduler:
*
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -3377,34 +3663,34 @@ public static Observable mergeDelayError(@NonNull Iterable the common element base type * @param sources - * an ObservableSource that emits ObservableSources - * @return an Observable that emits all of the items emitted by the ObservableSources emitted by the - * {@code source} ObservableSource + * an {@code ObservableSource} that emits {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @SuppressWarnings({ "unchecked", "rawtypes" }) @NonNull - public static Observable mergeDelayError(@NonNull ObservableSource> sources) { + public static <@NonNull T> Observable mergeDelayError(@NonNull ObservableSource> sources) { Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new ObservableFlatMap(sources, Functions.identity(), true, Integer.MAX_VALUE, bufferSize())); } /** - * Flattens an ObservableSource that emits ObservableSources into one ObservableSource, in a way that allows an Observer to - * receive all successfully emitted items from all of the source ObservableSources without being interrupted by + * Flattens an {@link ObservableSource} that emits {@code ObservableSource}s into one {@code Observable}, in a way that allows an {@link Observer} to + * receive all successfully emitted items from all of the emitted {@code ObservableSource}s without being interrupted by * an error notification from one of them, while limiting the - * number of concurrent subscriptions to these ObservableSources. + * number of concurrent subscriptions to these {@code ObservableSource}s. *

- * This behaves like {@link #merge(ObservableSource)} except that if any of the merged ObservableSources notify of an + * This behaves like {@link #merge(ObservableSource)} except that if any of the merged {@code ObservableSource}s notify of an * error via {@link Observer#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged ObservableSources have finished emitting items. + * error notification until all of the merged {@code ObservableSource}s have finished emitting items. *

- * + * *

- * Even if multiple merged ObservableSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Observers once. + * Even if multiple merged {@code ObservableSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its {@code Observer}s once. *

*
Scheduler:
*
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -3412,11 +3698,12 @@ public static Observable mergeDelayError(@NonNull ObservableSource the common element base type * @param sources - * an ObservableSource that emits ObservableSources + * an {@code ObservableSource} that emits {@code ObservableSource}s * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently - * @return an Observable that emits all of the items emitted by the ObservableSources emitted by the - * {@code source} ObservableSource + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: Merge * @since 2.0 */ @@ -3424,25 +3711,25 @@ public static Observable mergeDelayError(@NonNull ObservableSource Observable mergeDelayError(@NonNull ObservableSource> sources, int maxConcurrency) { + public static <@NonNull T> Observable mergeDelayError(@NonNull ObservableSource> sources, int maxConcurrency) { Objects.requireNonNull(sources, "sources is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); return RxJavaPlugins.onAssembly(new ObservableFlatMap(sources, Functions.identity(), true, maxConcurrency, bufferSize())); } /** - * Flattens two ObservableSources into one ObservableSource, in a way that allows an Observer to receive all - * successfully emitted items from each of the source ObservableSources without being interrupted by an error + * Flattens two {@link ObservableSource}s into one {@code Observable}, in a way that allows an {@link Observer} to receive all + * successfully emitted items from each of the {@code ObservableSource}s without being interrupted by an error * notification from one of them. *

- * This behaves like {@link #merge(ObservableSource, ObservableSource)} except that if any of the merged ObservableSources + * This behaves like {@link #merge(ObservableSource, ObservableSource)} except that if any of the merged {@code ObservableSource}s * notify of an error via {@link Observer#onError onError}, {@code mergeDelayError} will refrain from - * propagating that error notification until all of the merged ObservableSources have finished emitting items. + * propagating that error notification until all of the merged {@code ObservableSource}s have finished emitting items. *

- * + * *

- * Even if both merged ObservableSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Observers once. + * Even if both merged {@code ObservableSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its {@code Observer}s once. *

*
Scheduler:
*
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -3450,17 +3737,18 @@ public static Observable mergeDelayError(@NonNull ObservableSource the common element base type * @param source1 - * an ObservableSource to be merged + * an {@code ObservableSource} to be merged * @param source2 - * an ObservableSource to be merged - * @return an Observable that emits all of the items that are emitted by the two source ObservableSources + * an {@code ObservableSource} to be merged + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @see ReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable mergeDelayError( + public static <@NonNull T> Observable mergeDelayError( @NonNull ObservableSource source1, @NonNull ObservableSource source2) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); @@ -3468,19 +3756,19 @@ public static Observable mergeDelayError( } /** - * Flattens three ObservableSources into one ObservableSource, in a way that allows an Observer to receive all - * successfully emitted items from all of the source ObservableSources without being interrupted by an error + * Flattens three {@link ObservableSource}s into one {@code Observable}, in a way that allows an {@link Observer} to receive all + * successfully emitted items from all of the {@code ObservableSource}s without being interrupted by an error * notification from one of them. *

* This behaves like {@link #merge(ObservableSource, ObservableSource, ObservableSource)} except that if any of the merged - * ObservableSources notify of an error via {@link Observer#onError onError}, {@code mergeDelayError} will refrain - * from propagating that error notification until all of the merged ObservableSources have finished emitting + * {@code ObservableSource}s notify of an error via {@link Observer#onError onError}, {@code mergeDelayError} will refrain + * from propagating that error notification until all of the merged {@code ObservableSource}s have finished emitting * items. *

- * + * *

- * Even if multiple merged ObservableSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Observers once. + * Even if multiple merged {@code ObservableSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its {@code Observer}s once. *

*
Scheduler:
*
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -3488,19 +3776,20 @@ public static Observable mergeDelayError( * * @param the common element base type * @param source1 - * an ObservableSource to be merged + * an {@code ObservableSource} to be merged * @param source2 - * an ObservableSource to be merged + * an {@code ObservableSource} to be merged * @param source3 - * an ObservableSource to be merged - * @return an Observable that emits all of the items that are emitted by the source ObservableSources + * an {@code ObservableSource} to be merged + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} * @see ReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable mergeDelayError( + public static <@NonNull T> Observable mergeDelayError( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3) { Objects.requireNonNull(source1, "source1 is null"); @@ -3510,19 +3799,19 @@ public static Observable mergeDelayError( } /** - * Flattens four ObservableSources into one ObservableSource, in a way that allows an Observer to receive all - * successfully emitted items from all of the source ObservableSources without being interrupted by an error + * Flattens four {@link ObservableSource}s into one {@code Observable}, in a way that allows an {@link Observer} to receive all + * successfully emitted items from all of the {@code ObservableSource}s without being interrupted by an error * notification from one of them. *

* This behaves like {@link #merge(ObservableSource, ObservableSource, ObservableSource, ObservableSource)} except that if any of - * the merged ObservableSources notify of an error via {@link Observer#onError onError}, {@code mergeDelayError} - * will refrain from propagating that error notification until all of the merged ObservableSources have finished + * the merged {@code ObservableSource}s notify of an error via {@link Observer#onError onError}, {@code mergeDelayError} + * will refrain from propagating that error notification until all of the merged {@code ObservableSource}s have finished * emitting items. *

- * + * *

- * Even if multiple merged ObservableSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Observers once. + * Even if multiple merged {@code ObservableSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its {@code Observer}s once. *

*
Scheduler:
*
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -3530,21 +3819,22 @@ public static Observable mergeDelayError( * * @param the common element base type * @param source1 - * an ObservableSource to be merged + * an {@code ObservableSource} to be merged * @param source2 - * an ObservableSource to be merged + * an {@code ObservableSource} to be merged * @param source3 - * an ObservableSource to be merged + * an {@code ObservableSource} to be merged * @param source4 - * an ObservableSource to be merged - * @return an Observable that emits all of the items that are emitted by the source ObservableSources + * an {@code ObservableSource} to be merged + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} * @see ReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable mergeDelayError( + public static <@NonNull T> Observable mergeDelayError( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4) { Objects.requireNonNull(source1, "source1 is null"); @@ -3555,18 +3845,18 @@ public static Observable mergeDelayError( } /** - * Flattens an Iterable of ObservableSources into one ObservableSource, in a way that allows an Observer to receive all - * successfully emitted items from each of the source ObservableSources without being interrupted by an error + * Flattens an array of {@link ObservableSource}s into one {@code Observable}, in a way that allows an {@link Observer} to receive all + * successfully emitted items from each of the {@code ObservableSource}s without being interrupted by an error * notification from one of them. *

- * This behaves like {@link #merge(ObservableSource)} except that if any of the merged ObservableSources notify of an + * This behaves like {@link #merge(ObservableSource)} except that if any of the merged {@code ObservableSource}s notify of an * error via {@link Observer#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged ObservableSources have finished emitting items. + * error notification until all of the merged {@code ObservableSource}s have finished emitting items. *

- * + * *

- * Even if multiple merged ObservableSources send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its Observers once. + * Even if multiple merged {@code ObservableSource}s send {@code onError} notifications, {@code mergeDelayError} will only + * invoke the {@code onError} method of its {@code Observer}s once. *

*
Scheduler:
*
{@code mergeArrayDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -3574,9 +3864,9 @@ public static Observable mergeDelayError( * * @param the common element base type * @param sources - * the Iterable of ObservableSources - * @return an Observable that emits items that are the result of flattening the items emitted by the - * ObservableSources in the Iterable + * the array of {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -3584,52 +3874,54 @@ public static Observable mergeDelayError( @SchedulerSupport(SchedulerSupport.NONE) @NonNull @SafeVarargs - public static Observable mergeArrayDelayError(@NonNull ObservableSource... sources) { + public static <@NonNull T> Observable mergeArrayDelayError(@NonNull ObservableSource... sources) { return fromArray(sources).flatMap((Function)Functions.identity(), true, sources.length); } /** - * Returns an Observable that never sends any items or notifications to an {@link Observer}. + * Returns an {@code Observable} that never sends any items or notifications to an {@link Observer}. *

- * + * *

- * This ObservableSource is useful primarily for testing purposes. + * The returned {@code Observable} is useful primarily for testing purposes. *

*
Scheduler:
*
{@code never} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items (not) emitted by the ObservableSource - * @return an Observable that never emits any items or sends any notifications to an {@link Observer} + * the type of items (not) emitted by the {@code Observable} + * @return the shared {@code Observable} instance * @see ReactiveX operators documentation: Never */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @SuppressWarnings("unchecked") @NonNull - public static Observable never() { + public static <@NonNull T> Observable never() { return RxJavaPlugins.onAssembly((Observable) ObservableNever.INSTANCE); } /** - * Returns an Observable that emits a sequence of Integers within a specified range. + * Returns an {@code Observable} that emits a sequence of {@link Integer}s within a specified range. *

- * + * *

*
Scheduler:
*
{@code range} does not operate by default on a particular {@link Scheduler}.
*
* * @param start - * the value of the first Integer in the sequence + * the value of the first {@code Integer} in the sequence * @param count - * the number of sequential Integers to generate - * @return an Observable that emits a range of sequential Integers + * the number of sequential {@code Integer}s to generate + * @return the new {@code Observable} instance * @throws IllegalArgumentException - * if {@code count} is less than zero, or if {@code start} + {@code count} − 1 exceeds + * if {@code count} is negative, or if {@code start} + {@code count} − 1 exceeds * {@link Integer#MAX_VALUE} * @see ReactiveX operators documentation: Range + * @see #rangeLong(long, long) + * @see #intervalRange(long, long, long, long, TimeUnit) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -3651,7 +3943,7 @@ public static Observable range(int start, int count) { } /** - * Returns an Observable that emits a sequence of Longs within a specified range. + * Returns an {@code Observable} that emits a sequence of {@link Long}s within a specified range. *

* *

@@ -3660,14 +3952,15 @@ public static Observable range(int start, int count) { *
* * @param start - * the value of the first Long in the sequence + * the value of the first {@code Long} in the sequence * @param count - * the number of sequential Longs to generate - * @return an Observable that emits a range of sequential Longs + * the number of sequential {@code Long}s to generate + * @return the new {@code Observable} instance * @throws IllegalArgumentException - * if {@code count} is less than zero, or if {@code start} + {@code count} − 1 exceeds + * if {@code count} is negative, or if {@code start} + {@code count} − 1 exceeds * {@link Long#MAX_VALUE} * @see ReactiveX operators documentation: Range + * @see #intervalRange(long, long, long, long, TimeUnit) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -3694,92 +3987,94 @@ public static Observable rangeLong(long start, long count) { } /** - * Returns a Single that emits a Boolean value that indicates whether two ObservableSource sequences are the - * same by comparing the items emitted by each ObservableSource pairwise. + * Returns a {@link Single} that emits a {@link Boolean} value that indicates whether two {@link ObservableSource} sequences are the + * same by comparing the items emitted by each {@code ObservableSource} pairwise. *

- * + * *

*
Scheduler:
*
{@code sequenceEqual} does not operate by default on a particular {@link Scheduler}.
*
* * @param source1 - * the first ObservableSource to compare + * the first {@code ObservableSource} to compare * @param source2 - * the second ObservableSource to compare + * the second {@code ObservableSource} to compare * @param - * the type of items emitted by each ObservableSource - * @return a Single that emits a Boolean value that indicates whether the two sequences are the same + * the type of items emitted by each {@code ObservableSource} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @see ReactiveX operators documentation: SequenceEqual */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Single sequenceEqual(@NonNull ObservableSource source1, @NonNull ObservableSource source2) { + public static <@NonNull T> Single sequenceEqual(@NonNull ObservableSource source1, @NonNull ObservableSource source2) { return sequenceEqual(source1, source2, ObjectHelper.equalsPredicate(), bufferSize()); } /** - * Returns a Single that emits a Boolean value that indicates whether two ObservableSource sequences are the - * same by comparing the items emitted by each ObservableSource pairwise based on the results of a specified + * Returns a {@link Single} that emits a {@link Boolean} value that indicates whether two {@link ObservableSource} sequences are the + * same by comparing the items emitted by each {@code ObservableSource} pairwise based on the results of a specified * equality function. *

- * + * *

*
Scheduler:
*
{@code sequenceEqual} does not operate by default on a particular {@link Scheduler}.
*
* * @param source1 - * the first ObservableSource to compare + * the first {@code ObservableSource} to compare * @param source2 - * the second ObservableSource to compare + * the second {@code ObservableSource} to compare * @param isEqual - * a function used to compare items emitted by each ObservableSource + * a function used to compare items emitted by each {@code ObservableSource} * @param - * the type of items emitted by each ObservableSource - * @return a Single that emits a Boolean value that indicates whether the two ObservableSource two sequences - * are the same according to the specified function + * the type of items emitted by each {@code ObservableSource} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code isEqual} is {@code null} * @see ReactiveX operators documentation: SequenceEqual */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Single sequenceEqual( + public static <@NonNull T> Single sequenceEqual( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull BiPredicate isEqual) { return sequenceEqual(source1, source2, isEqual, bufferSize()); } /** - * Returns a Single that emits a Boolean value that indicates whether two ObservableSource sequences are the - * same by comparing the items emitted by each ObservableSource pairwise based on the results of a specified + * Returns a {@link Single} that emits a {@link Boolean} value that indicates whether two {@link ObservableSource} sequences are the + * same by comparing the items emitted by each {@code ObservableSource} pairwise based on the results of a specified * equality function. *

- * + * *

*
Scheduler:
*
{@code sequenceEqual} does not operate by default on a particular {@link Scheduler}.
*
* * @param source1 - * the first ObservableSource to compare + * the first {@code ObservableSource} to compare * @param source2 - * the second ObservableSource to compare + * the second {@code ObservableSource} to compare * @param isEqual - * a function used to compare items emitted by each ObservableSource + * a function used to compare items emitted by each {@code ObservableSource} * @param bufferSize - * the number of items to prefetch from the first and second source ObservableSource + * the number of items expected from the first and second source {@code ObservableSource} to be buffered * @param - * the type of items emitted by each ObservableSource - * @return an Observable that emits a Boolean value that indicates whether the two ObservableSource two sequences - * are the same according to the specified function + * the type of items emitted by each {@code ObservableSource} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code isEqual} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: SequenceEqual */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Single sequenceEqual( + public static <@NonNull T> Single sequenceEqual( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull BiPredicate isEqual, int bufferSize) { Objects.requireNonNull(source1, "source1 is null"); @@ -3790,47 +4085,49 @@ public static Single sequenceEqual( } /** - * Returns a Single that emits a Boolean value that indicates whether two ObservableSource sequences are the - * same by comparing the items emitted by each ObservableSource pairwise. + * Returns a {@link Single} that emits a {@link Boolean} value that indicates whether two {@link ObservableSource} sequences are the + * same by comparing the items emitted by each {@code ObservableSource} pairwise. *

- * + * *

*
Scheduler:
*
{@code sequenceEqual} does not operate by default on a particular {@link Scheduler}.
*
* * @param source1 - * the first ObservableSource to compare + * the first {@code ObservableSource} to compare * @param source2 - * the second ObservableSource to compare + * the second {@code ObservableSource} to compare * @param bufferSize - * the number of items to prefetch from the first and second source ObservableSource + * the number of items expected from the first and second source {@code ObservableSource} to be buffered * @param - * the type of items emitted by each ObservableSource - * @return a Single that emits a Boolean value that indicates whether the two sequences are the same + * the type of items emitted by each {@code ObservableSource} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: SequenceEqual */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Single sequenceEqual(@NonNull ObservableSource source1, @NonNull ObservableSource source2, + public static <@NonNull T> Single sequenceEqual(@NonNull ObservableSource source1, @NonNull ObservableSource source2, int bufferSize) { return sequenceEqual(source1, source2, ObjectHelper.equalsPredicate(), bufferSize); } /** - * Converts an ObservableSource that emits ObservableSources into an ObservableSource that emits the items emitted by the - * most recently emitted of those ObservableSources. + * Converts an {@link ObservableSource} that emits {@code ObservableSource}s into an {@code Observable} that emits the items emitted by the + * most recently emitted of those {@code ObservableSource}s. *

- * + * *

- * {@code switchOnNext} subscribes to an ObservableSource that emits ObservableSources. Each time it observes one of - * these emitted ObservableSources, the ObservableSource returned by {@code switchOnNext} begins emitting the items - * emitted by that ObservableSource. When a new ObservableSource is emitted, {@code switchOnNext} stops emitting items - * from the earlier-emitted ObservableSource and begins emitting items from the new one. + * {@code switchOnNext} subscribes to an {@code ObservableSource} that emits {@code ObservableSource}s. Each time it observes one of + * these emitted {@code ObservableSource}s, the {@code ObservableSource} returned by {@code switchOnNext} begins emitting the items + * emitted by that {@code ObservableSource}. When a new inner {@code ObservableSource} is emitted, {@code switchOnNext} stops emitting items + * from the earlier-emitted {@code ObservableSource} and begins emitting items from the new one. *

- * The resulting ObservableSource completes if both the outer ObservableSource and the last inner ObservableSource, if any, complete. - * If the outer ObservableSource signals an onError, the inner ObservableSource is disposed and the error delivered in-sequence. + * The resulting {@code Observable} completes if both the outer {@code ObservableSource} and the last inner {@code ObservableSource}, if any, complete. + * If the outer {@code ObservableSource} signals an {@code onError}, the inner {@code ObservableSource} is disposed and the error delivered in-sequence. *

*
Scheduler:
*
{@code switchOnNext} does not operate by default on a particular {@link Scheduler}.
@@ -3838,36 +4135,37 @@ public static Single sequenceEqual(@NonNull ObservableSource the item type * @param sources - * the source ObservableSource that emits ObservableSources + * the {@code ObservableSource} that emits {@code ObservableSource}s * @param bufferSize - * the number of items to prefetch from the inner ObservableSources - * @return an Observable that emits the items emitted by the ObservableSource most recently emitted by the source - * ObservableSource + * the expected number of items to cache from the inner {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Switch */ @SuppressWarnings({ "rawtypes", "unchecked" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable switchOnNext(@NonNull ObservableSource> sources, int bufferSize) { + public static <@NonNull T> Observable switchOnNext(@NonNull ObservableSource> sources, int bufferSize) { Objects.requireNonNull(sources, "sources is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); return RxJavaPlugins.onAssembly(new ObservableSwitchMap(sources, Functions.identity(), bufferSize, false)); } /** - * Converts an ObservableSource that emits ObservableSources into an ObservableSource that emits the items emitted by the - * most recently emitted of those ObservableSources. + * Converts an {@link ObservableSource} that emits {@code ObservableSource}s into an {@code Observable} that emits the items emitted by the + * most recently emitted of those {@code ObservableSource}s. *

- * + * *

- * {@code switchOnNext} subscribes to an ObservableSource that emits ObservableSources. Each time it observes one of - * these emitted ObservableSources, the ObservableSource returned by {@code switchOnNext} begins emitting the items - * emitted by that ObservableSource. When a new ObservableSource is emitted, {@code switchOnNext} stops emitting items - * from the earlier-emitted ObservableSource and begins emitting items from the new one. + * {@code switchOnNext} subscribes to an {@code ObservableSource} that emits {@code ObservableSource}s. Each time it observes one of + * these emitted {@code ObservableSource}s, the {@code ObservableSource} returned by {@code switchOnNext} begins emitting the items + * emitted by that {@code ObservableSource}. When a new inner {@code ObservableSource} is emitted, {@code switchOnNext} stops emitting items + * from the earlier-emitted {@code ObservableSource} and begins emitting items from the new one. *

- * The resulting ObservableSource completes if both the outer ObservableSource and the last inner ObservableSource, if any, complete. - * If the outer ObservableSource signals an onError, the inner ObservableSource is disposed and the error delivered in-sequence. + * The resulting {@code Observable} completes if both the outer {@code ObservableSource} and the last inner {@code ObservableSource}, if any, complete. + * If the outer {@code ObservableSource} signals an {@code onError}, the inner {@code ObservableSource} is disposed and the error delivered in-sequence. *

*
Scheduler:
*
{@code switchOnNext} does not operate by default on a particular {@link Scheduler}.
@@ -3875,32 +4173,32 @@ public static Observable switchOnNext(@NonNull ObservableSource the item type * @param sources - * the source ObservableSource that emits ObservableSources - * @return an Observable that emits the items emitted by the ObservableSource most recently emitted by the source - * ObservableSource + * the {@code ObservableSource} that emits {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Switch */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable switchOnNext(@NonNull ObservableSource> sources) { + public static <@NonNull T> Observable switchOnNext(@NonNull ObservableSource> sources) { return switchOnNext(sources, bufferSize()); } /** - * Converts an ObservableSource that emits ObservableSources into an ObservableSource that emits the items emitted by the - * most recently emitted of those ObservableSources and delays any exception until all ObservableSources terminate. + * Converts an {@link ObservableSource} that emits {@code ObservableSource}s into an {@code Observable} that emits the items emitted by the + * most recently emitted of those {@code ObservableSource}s and delays any exception until all {@code ObservableSource}s terminate. *

- * + * *

- * {@code switchOnNext} subscribes to an ObservableSource that emits ObservableSources. Each time it observes one of - * these emitted ObservableSources, the ObservableSource returned by {@code switchOnNext} begins emitting the items - * emitted by that ObservableSource. When a new ObservableSource is emitted, {@code switchOnNext} stops emitting items - * from the earlier-emitted ObservableSource and begins emitting items from the new one. + * {@code switchOnNext} subscribes to an {@code ObservableSource} that emits {@code ObservableSource}s. Each time it observes one of + * these emitted {@code ObservableSource}s, the {@code ObservableSource} returned by {@code switchOnNext} begins emitting the items + * emitted by that {@code ObservableSource}. When a new inner {@code ObservableSource} is emitted, {@code switchOnNext} stops emitting items + * from the earlier-emitted {@code ObservableSource} and begins emitting items from the new one. *

- * The resulting ObservableSource completes if both the main ObservableSource and the last inner ObservableSource, if any, complete. - * If the main ObservableSource signals an onError, the termination of the last inner ObservableSource will emit that error as is - * or wrapped into a CompositeException along with the other possible errors the former inner ObservableSources signalled. + * The resulting {@code Observable} completes if both the main {@code ObservableSource} and the last inner {@code ObservableSource}, if any, complete. + * If the main {@code ObservableSource} signals an {@code onError}, the termination of the last inner {@code ObservableSource} will emit that error as is + * or wrapped into a {@link CompositeException} along with the other possible errors the former inner {@code ObservableSource}s signaled. *

*
Scheduler:
*
{@code switchOnNextDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -3908,33 +4206,33 @@ public static Observable switchOnNext(@NonNull ObservableSource the item type * @param sources - * the source ObservableSource that emits ObservableSources - * @return an Observable that emits the items emitted by the ObservableSource most recently emitted by the source - * ObservableSource + * the {@code ObservableSource} that emits {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Switch * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable switchOnNextDelayError(@NonNull ObservableSource> sources) { + public static <@NonNull T> Observable switchOnNextDelayError(@NonNull ObservableSource> sources) { return switchOnNextDelayError(sources, bufferSize()); } /** - * Converts an ObservableSource that emits ObservableSources into an ObservableSource that emits the items emitted by the - * most recently emitted of those ObservableSources and delays any exception until all ObservableSources terminate. + * Converts an {@link ObservableSource} that emits {@code ObservableSource}s into an {@code Observable} that emits the items emitted by the + * most recently emitted of those {@code ObservableSource}s and delays any exception until all {@code ObservableSource}s terminate. *

- * + * *

- * {@code switchOnNext} subscribes to an ObservableSource that emits ObservableSources. Each time it observes one of - * these emitted ObservableSources, the ObservableSource returned by {@code switchOnNext} begins emitting the items - * emitted by that ObservableSource. When a new ObservableSource is emitted, {@code switchOnNext} stops emitting items - * from the earlier-emitted ObservableSource and begins emitting items from the new one. + * {@code switchOnNext} subscribes to an {@code ObservableSource} that emits {@code ObservableSource}s. Each time it observes one of + * these emitted {@code ObservableSource}s, the {@code ObservableSource} returned by {@code switchOnNext} begins emitting the items + * emitted by that {@code ObservableSource}. When a new inner {@code ObservableSource} is emitted, {@code switchOnNext} stops emitting items + * from the earlier-emitted {@code ObservableSource} and begins emitting items from the new one. *

- * The resulting ObservableSource completes if both the main ObservableSource and the last inner ObservableSource, if any, complete. - * If the main ObservableSource signals an onError, the termination of the last inner ObservableSource will emit that error as is - * or wrapped into a CompositeException along with the other possible errors the former inner ObservableSources signalled. + * The resulting {@code Observable} completes if both the main {@code ObservableSource} and the last inner {@code ObservableSource}, if any, complete. + * If the main {@code ObservableSource} signals an {@code onError}, the termination of the last inner {@code ObservableSource} will emit that error as is + * or wrapped into a {@link CompositeException} along with the other possible errors the former inner {@code ObservableSource}s signaled. *

*
Scheduler:
*
{@code switchOnNextDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -3942,11 +4240,12 @@ public static Observable switchOnNextDelayError(@NonNull ObservableSource * * @param the item type * @param sources - * the source ObservableSource that emits ObservableSources - * @param prefetch - * the number of items to prefetch from the inner ObservableSources - * @return an Observable that emits the items emitted by the ObservableSource most recently emitted by the source - * ObservableSource + * the {@code ObservableSource} that emits {@code ObservableSource}s + * @param bufferSize + * the expected number of items to cache from the inner {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Switch * @since 2.0 */ @@ -3954,16 +4253,16 @@ public static Observable switchOnNextDelayError(@NonNull ObservableSource @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable switchOnNextDelayError(@NonNull ObservableSource> sources, int prefetch) { + public static <@NonNull T> Observable switchOnNextDelayError(@NonNull ObservableSource> sources, int bufferSize) { Objects.requireNonNull(sources, "sources is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new ObservableSwitchMap(sources, Functions.identity(), prefetch, true)); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + return RxJavaPlugins.onAssembly(new ObservableSwitchMap(sources, Functions.identity(), bufferSize, true)); } /** - * Returns an Observable that emits {@code 0L} after a specified delay, and then completes. + * Returns an {@code Observable} that emits {@code 0L} after a specified delay, and then completes. *

- * + * *

*
Scheduler:
*
{@code timer} operates by default on the {@code computation} {@link Scheduler}.
@@ -3973,7 +4272,8 @@ public static Observable switchOnNextDelayError(@NonNull ObservableSource * the initial delay before emitting a single {@code 0L} * @param unit * time units to use for {@code delay} - * @return an Observable that {@code 0L} after a specified delay, and then completes + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Timer */ @CheckReturnValue @@ -3984,13 +4284,13 @@ public static Observable timer(long delay, @NonNull TimeUnit unit) { } /** - * Returns an Observable that emits {@code 0L} after a specified delay, on a specified Scheduler, and then + * Returns an {@code Observable} that emits {@code 0L} after a specified delay, on a specified {@link Scheduler}, and then * completes. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param delay @@ -3998,12 +4298,10 @@ public static Observable timer(long delay, @NonNull TimeUnit unit) { * @param unit * time units to use for {@code delay} * @param scheduler - * the {@link Scheduler} to use for scheduling the item + * the {@code Scheduler} to use for scheduling the item * @throws NullPointerException - * if {@code unit} is null, or - * if {@code scheduler} is null - * @return an Observable that emits {@code 0L} after a specified delay, on a specified Scheduler, and then - * completes + * if {@code unit} or {@code scheduler} is {@code null} + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Timer */ @CheckReturnValue @@ -4017,21 +4315,25 @@ public static Observable timer(long delay, @NonNull TimeUnit unit, @NonNul } /** - * Create an Observable by wrapping an ObservableSource which has to be implemented according - * to the Reactive-Streams-based Observable specification by handling - * disposal correctly; no safeguards are provided by the Observable itself. + * Create an {@code Observable} by wrapping an {@link ObservableSource} which has to be implemented according + * to the {@code Observable} specification derived from the Reactive Streams specification by handling + * disposal correctly; no safeguards are provided by the {@code Observable} itself. *
*
Scheduler:
*
{@code unsafeCreate} by default doesn't operate on any particular {@link Scheduler}.
*
* @param the value type emitted - * @param onSubscribe the ObservableSource instance to wrap - * @return the new Observable instance + * @param onSubscribe the {@code ObservableSource} instance to wrap + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onSubscribe} is {@code null} + * @throws IllegalArgumentException if the {@code onSubscribe} is already an {@code Observable}, use + * {@link #wrap(ObservableSource)} in this case + * @see #wrap(ObservableSource) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable unsafeCreate(@NonNull ObservableSource onSubscribe) { + public static <@NonNull T> Observable unsafeCreate(@NonNull ObservableSource onSubscribe) { Objects.requireNonNull(onSubscribe, "onSubscribe is null"); if (onSubscribe instanceof Observable) { throw new IllegalArgumentException("unsafeCreate(Observable) should be upgraded"); @@ -4040,81 +4342,82 @@ public static Observable unsafeCreate(@NonNull ObservableSource onSubs } /** - * Constructs an ObservableSource that creates a dependent resource object which is disposed of when the downstream - * calls dispose(). + * Constructs an {@code Observable} that creates a dependent resource object, an {@link ObservableSource} with + * that resource and calls the provided {@code resourceDisposer} function if this inner source terminates or the + * downstream disposes the flow. *

- * + * *

*
Scheduler:
*
{@code using} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the element type of the generated ObservableSource + * @param the element type of the generated {@code Observable} * @param the type of the resource associated with the output sequence * @param resourceSupplier - * the factory function to create a resource object that depends on the ObservableSource + * the factory function to create a resource object that depends on the {@code ObservableSource} * @param sourceSupplier - * the factory function to create an ObservableSource - * @param disposer + * the factory function to create an {@code ObservableSource} + * @param resourceCleanup * the function that will dispose of the resource - * @return the ObservableSource whose lifetime controls the lifetime of the dependent resource object + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code resourceSupplier}, {@code sourceSupplier} or {@code resourceCleanup} is {@code null} * @see ReactiveX operators documentation: Using */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable using( + public static <@NonNull T, @NonNull D> Observable using( @NonNull Supplier resourceSupplier, @NonNull Function> sourceSupplier, - @NonNull Consumer disposer) { - return using(resourceSupplier, sourceSupplier, disposer, true); + @NonNull Consumer resourceCleanup) { + return using(resourceSupplier, sourceSupplier, resourceCleanup, true); } /** - * Constructs an ObservableSource that creates a dependent resource object which is disposed of just before - * termination if you have set {@code disposeEagerly} to {@code true} and a dispose() call does not occur - * before termination. Otherwise resource disposal will occur on a dispose() call. Eager disposal is - * particularly appropriate for a synchronous ObservableSource that reuses resources. {@code disposeAction} will - * only be called once per subscription. + * Constructs an {@code Observable} that creates a dependent resource object, an {@link ObservableSource} with + * that resource and calls the provided {@code disposer} function if this inner source terminates or the + * downstream disposes the flow; doing it before these end-states have been reached if {@code eager == true}, after otherwise. *

- * + * *

*
Scheduler:
*
{@code using} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the element type of the generated ObservableSource + * @param the element type of the generated {@code ObservableSource} * @param the type of the resource associated with the output sequence * @param resourceSupplier - * the factory function to create a resource object that depends on the ObservableSource + * the factory function to create a resource object that depends on the {@code ObservableSource} * @param sourceSupplier - * the factory function to create an ObservableSource - * @param disposer + * the factory function to create an {@code ObservableSource} + * @param resourceCleanup * the function that will dispose of the resource * @param eager - * If {@code true} then resource disposal will happen either on a {@code dispose()} call before the upstream is disposed + * If {@code true}, the resource disposal will happen either on a {@code dispose()} call before the upstream is disposed * or just before the emission of a terminal event ({@code onComplete} or {@code onError}). - * If {@code false} the resource disposal will happen either on a {@code dispose()} call after the upstream is disposed + * If {@code false}, the resource disposal will happen either on a {@code dispose()} call after the upstream is disposed * or just after the emission of a terminal event ({@code onComplete} or {@code onError}). - * @return the ObservableSource whose lifetime controls the lifetime of the dependent resource object + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code resourceSupplier}, {@code sourceSupplier} and {@code resourceCleanup} is {@code null} * @see ReactiveX operators documentation: Using * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable using( + public static <@NonNull T, @NonNull D> Observable using( @NonNull Supplier resourceSupplier, @NonNull Function> sourceSupplier, - @NonNull Consumer disposer, boolean eager) { + @NonNull Consumer resourceCleanup, boolean eager) { Objects.requireNonNull(resourceSupplier, "resourceSupplier is null"); Objects.requireNonNull(sourceSupplier, "sourceSupplier is null"); - Objects.requireNonNull(disposer, "disposer is null"); - return RxJavaPlugins.onAssembly(new ObservableUsing(resourceSupplier, sourceSupplier, disposer, eager)); + Objects.requireNonNull(resourceCleanup, "resourceCleanup is null"); + return RxJavaPlugins.onAssembly(new ObservableUsing(resourceSupplier, sourceSupplier, resourceCleanup, eager)); } /** - * Wraps an ObservableSource into an Observable if not already an Observable. + * Wraps an {@link ObservableSource} into an {@code Observable} if not already an {@code Observable}. * *
*
Scheduler:
@@ -4122,14 +4425,14 @@ public static Observable using( *
* * @param the value type - * @param source the source ObservableSource instance - * @return the new Observable instance or the same as the source - * @throws NullPointerException if source is null + * @param source the {@code ObservableSource} instance to wrap or cast to {@code Observable} + * @return the new {@code Observable} instance or the same as the source + * @throws NullPointerException if {@code source} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable wrap(@NonNull ObservableSource source) { + public static <@NonNull T> Observable wrap(@NonNull ObservableSource source) { Objects.requireNonNull(source, "source is null"); if (source instanceof Observable) { return RxJavaPlugins.onAssembly((Observable)source); @@ -4138,16 +4441,16 @@ public static Observable wrap(@NonNull ObservableSource source) { } /** - * Returns an Observable that emits the results of a specified combiner function applied to combinations of - * items emitted, in sequence, by an Iterable of other ObservableSources. + * Returns an {@code Observable} that emits the results of a specified combiner function applied to combinations of + * items emitted, in sequence, by an {@link Iterable} of other {@link ObservableSource}s. *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new ObservableSource - * will be the result of the function applied to the first item emitted by each of the source ObservableSources; - * the second item emitted by the new ObservableSource will be the result of the function applied to the second - * item emitted by each of those ObservableSources; and so forth. + * {@code zip} applies this function in strict sequence, so the first item emitted by the resulting {@code Observable} + * will be the result of the function applied to the first item emitted by each of the {@code ObservableSource}s; + * the second item emitted by the resulting {@code Observable} will be the result of the function applied to the second + * item emitted by each of those {@code ObservableSource}s; and so forth. *

- * The resulting {@code ObservableSource} returned from {@code zip} will invoke {@code onNext} as many times as - * the number of {@code onNext} invocations of the source ObservableSource that emits the fewest items. + * The resulting {@code Observable} returned from {@code zip} will invoke {@code onNext} as many times as + * the number of {@code onNext} invocations of the {@code ObservableSource} that emits the fewest items. *

* The operator subscribes to its sources in order they are specified and completes eagerly if * one of the sources is shorter than the rest while disposing the other sources. Therefore, it @@ -4163,10 +4466,10 @@ public static Observable wrap(@NonNull ObservableSource source) { *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. * *

- * + * *

*
Scheduler:
*
{@code zip} does not operate by default on a particular {@link Scheduler}.
@@ -4175,33 +4478,34 @@ public static Observable wrap(@NonNull ObservableSource source) { * @param the common value type * @param the zipped result type * @param sources - * an Iterable of source ObservableSources + * an {@code Iterable} of source {@code ObservableSource}s * @param zipper - * a function that, when applied to an item emitted by each of the source ObservableSources, results in - * an item that will be emitted by the resulting ObservableSource - * @return an Observable that emits the zipped results + * a function that, when applied to an item emitted by each of the {@code ObservableSource}s, results in + * an item that will be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable zip(@NonNull Iterable> sources, @NonNull Function zipper) { + public static <@NonNull T, @NonNull R> Observable zip(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, @NonNull Function zipper) { Objects.requireNonNull(zipper, "zipper is null"); Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new ObservableZip<>(null, sources, zipper, bufferSize(), false)); } /** - * Returns an Observable that emits the results of a specified combiner function applied to combinations of - * items emitted, in sequence, by an Iterable of other ObservableSources. + * Returns an {@code Observable} that emits the results of a specified combiner function applied to combinations of + * items emitted, in sequence, by an {@link Iterable} of other {@link ObservableSource}s. *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new ObservableSource - * will be the result of the function applied to the first item emitted by each of the source ObservableSources; - * the second item emitted by the new ObservableSource will be the result of the function applied to the second - * item emitted by each of those ObservableSources; and so forth. + * {@code zip} applies this function in strict sequence, so the first item emitted by the resulting {@code Observable} + * will be the result of the function applied to the first item emitted by each of the {@code ObservableSource}s; + * the second item emitted by the resulting {@code Observable} will be the result of the function applied to the second + * item emitted by each of those {@code ObservableSource}s; and so forth. *

- * The resulting {@code ObservableSource} returned from {@code zip} will invoke {@code onNext} as many times as - * the number of {@code onNext} invocations of the source ObservableSource that emits the fewest items. + * The resulting {@code Observable} returned from {@code zip} will invoke {@code onNext} as many times as + * the number of {@code onNext} invocations of the {@code ObservableSource} that emits the fewest items. *

* The operator subscribes to its sources in order they are specified and completes eagerly if * one of the sources is shorter than the rest while disposing the other sources. Therefore, it @@ -4217,10 +4521,10 @@ public static Observable zip(@NonNull Iterable * Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. * *

- * + * *

*
Scheduler:
*
{@code zip} does not operate by default on a particular {@link Scheduler}.
@@ -4228,23 +4532,25 @@ public static Observable zip(@NonNull Iterable the common source value type * @param the zipped result type - * @return an Observable that emits the zipped results + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} or {@code zipper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable zip(@NonNull Iterable> sources, + public static <@NonNull T, @NonNull R> Observable zip(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, @NonNull Function zipper, boolean delayError, int bufferSize) { Objects.requireNonNull(zipper, "zipper is null"); @@ -4254,18 +4560,18 @@ public static Observable zip(@NonNull Iterable - * + * *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new ObservableSource + * {@code zip} applies this function in strict sequence, so the first item emitted by the resulting {@code Observable} * will be the result of the function applied to the first item emitted by {@code o1} and the first item - * emitted by {@code o2}; the second item emitted by the new ObservableSource will be the result of the function + * emitted by {@code o2}; the second item emitted by the resulting {@code Observable} will be the result of the function * applied to the second item emitted by {@code o1} and the second item emitted by {@code o2}; and so forth. *

- * The resulting {@code ObservableSource} returned from {@code zip} will invoke {@link Observer#onNext onNext} - * as many times as the number of {@code onNext} invocations of the source ObservableSource that emits the fewest + * The resulting {@code Observable} returned from {@code zip} will invoke {@link Observer#onNext onNext} + * as many times as the number of {@code onNext} invocations of the {@code ObservableSource} that emits the fewest * items. *

* The operator subscribes to its sources in order they are specified and completes eagerly if @@ -4288,19 +4594,20 @@ public static Observable zip(@NonNull Iterable the value type of the second source * @param the zipped result type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * a second source ObservableSource + * a second source {@code ObservableSource} * @param zipper - * a function that, when applied to an item emitted by each of the source ObservableSources, results - * in an item that will be emitted by the resulting ObservableSource - * @return an Observable that emits the zipped results + * a function that, when applied to an item emitted by each of the {@code ObservableSource}s, results + * in an item that will be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable zip( + public static <@NonNull T1, @NonNull T2, @NonNull R> Observable zip( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull BiFunction zipper) { Objects.requireNonNull(source1, "source1 is null"); @@ -4310,18 +4617,18 @@ public static Observable zip( } /** - * Returns an Observable that emits the results of a specified combiner function applied to combinations of - * two items emitted, in sequence, by two other ObservableSources. + * Returns an {@code Observable} that emits the results of a specified combiner function applied to combinations of + * two items emitted, in sequence, by two other {@link ObservableSource}s. *

- * + * *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new ObservableSource + * {@code zip} applies this function in strict sequence, so the first item emitted by the resulting {@code Observable} * will be the result of the function applied to the first item emitted by {@code o1} and the first item - * emitted by {@code o2}; the second item emitted by the new ObservableSource will be the result of the function + * emitted by {@code o2}; the second item emitted by the resulting {@code Observable} will be the result of the function * applied to the second item emitted by {@code o1} and the second item emitted by {@code o2}; and so forth. *

- * The resulting {@code ObservableSource} returned from {@code zip} will invoke {@link Observer#onNext onNext} - * as many times as the number of {@code onNext} invocations of the source ObservableSource that emits the fewest + * The resulting {@code Observable} returned from {@code zip} will invoke {@link Observer#onNext onNext} + * as many times as the number of {@code onNext} invocations of the {@code ObservableSource} that emits the fewest * items. *

* The operator subscribes to its sources in order they are specified and completes eagerly if @@ -4344,20 +4651,21 @@ public static Observable zip( * @param the value type of the second source * @param the zipped result type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * a second source ObservableSource + * a second source {@code ObservableSource} * @param zipper - * a function that, when applied to an item emitted by each of the source ObservableSources, results - * in an item that will be emitted by the resulting ObservableSource - * @param delayError delay errors from any of the source ObservableSources till the other terminates - * @return an Observable that emits the zipped results + * a function that, when applied to an item emitted by each of the {@code ObservableSource}s, results + * in an item that will be emitted by the resulting {@code Observable} + * @param delayError delay errors from any of the {@code ObservableSource}s till the other terminates + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable zip( + public static <@NonNull T1, @NonNull T2, @NonNull R> Observable zip( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull BiFunction zipper, boolean delayError) { Objects.requireNonNull(source1, "source1 is null"); @@ -4367,18 +4675,18 @@ public static Observable zip( } /** - * Returns an Observable that emits the results of a specified combiner function applied to combinations of - * two items emitted, in sequence, by two other ObservableSources. + * Returns an {@code Observable} that emits the results of a specified combiner function applied to combinations of + * two items emitted, in sequence, by two other {@link ObservableSource}s. *

- * + * *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new ObservableSource + * {@code zip} applies this function in strict sequence, so the first item emitted by the resulting {@code Observable} * will be the result of the function applied to the first item emitted by {@code o1} and the first item - * emitted by {@code o2}; the second item emitted by the new ObservableSource will be the result of the function + * emitted by {@code o2}; the second item emitted by the resulting {@code Observable} will be the result of the function * applied to the second item emitted by {@code o1} and the second item emitted by {@code o2}; and so forth. *

- * The resulting {@code ObservableSource} returned from {@code zip} will invoke {@link Observer#onNext onNext} - * as many times as the number of {@code onNext} invocations of the source ObservableSource that emits the fewest + * The resulting {@code Observable} returned from {@code zip} will invoke {@link Observer#onNext onNext} + * as many times as the number of {@code onNext} invocations of the {@code ObservableSource} that emits the fewest * items. *

* The operator subscribes to its sources in order they are specified and completes eagerly if @@ -4401,21 +4709,23 @@ public static Observable zip( * @param the value type of the second source * @param the zipped result type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * a second source ObservableSource + * a second source {@code ObservableSource} * @param zipper - * a function that, when applied to an item emitted by each of the source ObservableSources, results - * in an item that will be emitted by the resulting ObservableSource - * @param delayError delay errors from any of the source ObservableSources till the other terminates - * @param bufferSize the number of elements to prefetch from each source ObservableSource - * @return an Observable that emits the zipped results + * a function that, when applied to an item emitted by each of the {@code ObservableSource}s, results + * in an item that will be emitted by the resulting {@code Observable} + * @param delayError delay errors from any of the {@code ObservableSource}s till the other terminates + * @param bufferSize the number of elements expected from each source {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code zipper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable zip( + public static <@NonNull T1, @NonNull T2, @NonNull R> Observable zip( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull BiFunction zipper, boolean delayError, int bufferSize) { Objects.requireNonNull(source1, "source1 is null"); @@ -4425,19 +4735,19 @@ public static Observable zip( } /** - * Returns an Observable that emits the results of a specified combiner function applied to combinations of - * three items emitted, in sequence, by three other ObservableSources. + * Returns an {@code Observable} that emits the results of a specified combiner function applied to combinations of + * three items emitted, in sequence, by three other {@link ObservableSource}s. *

- * + * *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new ObservableSource + * {@code zip} applies this function in strict sequence, so the first item emitted by the resulting {@code Observable} * will be the result of the function applied to the first item emitted by {@code o1}, the first item - * emitted by {@code o2}, and the first item emitted by {@code o3}; the second item emitted by the new - * ObservableSource will be the result of the function applied to the second item emitted by {@code o1}, the + * emitted by {@code o2}, and the first item emitted by {@code o3}; the second item emitted by the resulting + * {@code Observable} will be the result of the function applied to the second item emitted by {@code o1}, the * second item emitted by {@code o2}, and the second item emitted by {@code o3}; and so forth. *

- * The resulting {@code ObservableSource} returned from {@code zip} will invoke {@link Observer#onNext onNext} - * as many times as the number of {@code onNext} invocations of the source ObservableSource that emits the fewest + * The resulting {@code Observable} returned from {@code zip} will invoke {@link Observer#onNext onNext} + * as many times as the number of {@code onNext} invocations of the {@code ObservableSource} that emits the fewest * items. *

* The operator subscribes to its sources in order they are specified and completes eagerly if @@ -4461,21 +4771,22 @@ public static Observable zip( * @param the value type of the third source * @param the zipped result type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * a second source ObservableSource + * a second source {@code ObservableSource} * @param source3 - * a third source ObservableSource + * a third source {@code ObservableSource} * @param zipper - * a function that, when applied to an item emitted by each of the source ObservableSources, results in - * an item that will be emitted by the resulting ObservableSource - * @return an Observable that emits the zipped results + * a function that, when applied to an item emitted by each of the {@code ObservableSource}s, results in + * an item that will be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull R> Observable zip( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull Function3 zipper) { @@ -4487,19 +4798,19 @@ public static Observable zip( } /** - * Returns an Observable that emits the results of a specified combiner function applied to combinations of - * four items emitted, in sequence, by four other ObservableSources. + * Returns an {@code Observable} that emits the results of a specified combiner function applied to combinations of + * four items emitted, in sequence, by four other {@link ObservableSource}s. *

- * + * *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new ObservableSource + * {@code zip} applies this function in strict sequence, so the first item emitted by the resulting {@code Observable} * will be the result of the function applied to the first item emitted by {@code o1}, the first item * emitted by {@code o2}, the first item emitted by {@code o3}, and the first item emitted by {@code 04}; - * the second item emitted by the new ObservableSource will be the result of the function applied to the second - * item emitted by each of those ObservableSources; and so forth. + * the second item emitted by the resulting {@code Observable} will be the result of the function applied to the second + * item emitted by each of those {@code ObservableSource}s; and so forth. *

- * The resulting {@code ObservableSource} returned from {@code zip} will invoke {@link Observer#onNext onNext} - * as many times as the number of {@code onNext} invocations of the source ObservableSource that emits the fewest + * The resulting {@code Observable} returned from {@code zip} will invoke {@link Observer#onNext onNext} + * as many times as the number of {@code onNext} invocations of the {@code ObservableSource} that emits the fewest * items. *

* The operator subscribes to its sources in order they are specified and completes eagerly if @@ -4524,23 +4835,25 @@ public static Observable zip( * @param the value type of the fourth source * @param the zipped result type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * a second source ObservableSource + * a second source {@code ObservableSource} * @param source3 - * a third source ObservableSource + * a third source {@code ObservableSource} * @param source4 - * a fourth source ObservableSource + * a fourth source {@code ObservableSource} * @param zipper - * a function that, when applied to an item emitted by each of the source ObservableSources, results in - * an item that will be emitted by the resulting ObservableSource - * @return an Observable that emits the zipped results + * a function that, when applied to an item emitted by each of the {@code ObservableSource}s, results in + * an item that will be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull R> Observable zip( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4, @NonNull Function4 zipper) { @@ -4553,19 +4866,19 @@ public static Observable zip( } /** - * Returns an Observable that emits the results of a specified combiner function applied to combinations of - * five items emitted, in sequence, by five other ObservableSources. + * Returns an {@code Observable} that emits the results of a specified combiner function applied to combinations of + * five items emitted, in sequence, by five other {@link ObservableSource}s. *

- * + * *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new ObservableSource + * {@code zip} applies this function in strict sequence, so the first item emitted by the resulting {@code Observable} * will be the result of the function applied to the first item emitted by {@code o1}, the first item * emitted by {@code o2}, the first item emitted by {@code o3}, the first item emitted by {@code o4}, and - * the first item emitted by {@code o5}; the second item emitted by the new ObservableSource will be the result of - * the function applied to the second item emitted by each of those ObservableSources; and so forth. + * the first item emitted by {@code o5}; the second item emitted by the resulting {@code Observable} will be the result of + * the function applied to the second item emitted by each of those {@code ObservableSource}s; and so forth. *

- * The resulting {@code ObservableSource} returned from {@code zip} will invoke {@link Observer#onNext onNext} - * as many times as the number of {@code onNext} invocations of the source ObservableSource that emits the fewest + * The resulting {@code Observable} returned from {@code zip} will invoke {@link Observer#onNext onNext} + * as many times as the number of {@code onNext} invocations of the {@code ObservableSource} that emits the fewest * items. *

* The operator subscribes to its sources in order they are specified and completes eagerly if @@ -4591,25 +4904,27 @@ public static Observable zip( * @param the value type of the fifth source * @param the zipped result type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * a second source ObservableSource + * a second source {@code ObservableSource} * @param source3 - * a third source ObservableSource + * a third source {@code ObservableSource} * @param source4 - * a fourth source ObservableSource + * a fourth source {@code ObservableSource} * @param source5 - * a fifth source ObservableSource + * a fifth source {@code ObservableSource} * @param zipper - * a function that, when applied to an item emitted by each of the source ObservableSources, results in - * an item that will be emitted by the resulting ObservableSource - * @return an Observable that emits the zipped results + * a function that, when applied to an item emitted by each of the {@code ObservableSource}s, results in + * an item that will be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull R> Observable zip( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4, @NonNull ObservableSource source5, @NonNull Function5 zipper) { @@ -4623,18 +4938,18 @@ public static Observable zip( } /** - * Returns an Observable that emits the results of a specified combiner function applied to combinations of - * six items emitted, in sequence, by six other ObservableSources. + * Returns an {@code Observable} that emits the results of a specified combiner function applied to combinations of + * six items emitted, in sequence, by six other {@link ObservableSource}s. *

- * + * *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new ObservableSource - * will be the result of the function applied to the first item emitted by each source ObservableSource, the - * second item emitted by the new ObservableSource will be the result of the function applied to the second item - * emitted by each of those ObservableSources, and so forth. + * {@code zip} applies this function in strict sequence, so the first item emitted by the resulting {@code Observable} + * will be the result of the function applied to the first item emitted by each source {@code ObservableSource}, the + * second item emitted by the resulting {@code Observable} will be the result of the function applied to the second item + * emitted by each of those {@code ObservableSource}s, and so forth. *

- * The resulting {@code ObservableSource} returned from {@code zip} will invoke {@link Observer#onNext onNext} - * as many times as the number of {@code onNext} invocations of the source ObservableSource that emits the fewest + * The resulting {@code Observable} returned from {@code zip} will invoke {@link Observer#onNext onNext} + * as many times as the number of {@code onNext} invocations of the {@code ObservableSource} that emits the fewest * items. *

* The operator subscribes to its sources in order they are specified and completes eagerly if @@ -4661,27 +4976,29 @@ public static Observable zip( * @param the value type of the sixth source * @param the zipped result type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * a second source ObservableSource + * a second source {@code ObservableSource} * @param source3 - * a third source ObservableSource + * a third source {@code ObservableSource} * @param source4 - * a fourth source ObservableSource + * a fourth source {@code ObservableSource} * @param source5 - * a fifth source ObservableSource + * a fifth source {@code ObservableSource} * @param source6 - * a sixth source ObservableSource + * a sixth source {@code ObservableSource} * @param zipper - * a function that, when applied to an item emitted by each of the source ObservableSources, results in - * an item that will be emitted by the resulting ObservableSource - * @return an Observable that emits the zipped results + * a function that, when applied to an item emitted by each of the {@code ObservableSource}s, results in + * an item that will be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull R> Observable zip( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4, @NonNull ObservableSource source5, @NonNull ObservableSource source6, @NonNull Function6 zipper) { @@ -4696,18 +5013,18 @@ public static Observable zip( } /** - * Returns an Observable that emits the results of a specified combiner function applied to combinations of - * seven items emitted, in sequence, by seven other ObservableSources. + * Returns an {@code Observable} that emits the results of a specified combiner function applied to combinations of + * seven items emitted, in sequence, by seven other {@link ObservableSource}s. *

- * + * *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new ObservableSource - * will be the result of the function applied to the first item emitted by each source ObservableSource, the - * second item emitted by the new ObservableSource will be the result of the function applied to the second item - * emitted by each of those ObservableSources, and so forth. + * {@code zip} applies this function in strict sequence, so the first item emitted by the resulting {@code Observable} + * will be the result of the function applied to the first item emitted by each source {@code ObservableSource}, the + * second item emitted by the resulting {@code Observable} will be the result of the function applied to the second item + * emitted by each of those {@code ObservableSource}s, and so forth. *

- * The resulting {@code ObservableSource} returned from {@code zip} will invoke {@link Observer#onNext onNext} - * as many times as the number of {@code onNext} invocations of the source ObservableSource that emits the fewest + * The resulting {@code Observable} returned from {@code zip} will invoke {@link Observer#onNext onNext} + * as many times as the number of {@code onNext} invocations of the {@code ObservableSource} that emits the fewest * items. *

* The operator subscribes to its sources in order they are specified and completes eagerly if @@ -4735,29 +5052,32 @@ public static Observable zip( * @param the value type of the seventh source * @param the zipped result type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * a second source ObservableSource + * a second source {@code ObservableSource} * @param source3 - * a third source ObservableSource + * a third source {@code ObservableSource} * @param source4 - * a fourth source ObservableSource + * a fourth source {@code ObservableSource} * @param source5 - * a fifth source ObservableSource + * a fifth source {@code ObservableSource} * @param source6 - * a sixth source ObservableSource + * a sixth source {@code ObservableSource} * @param source7 - * a seventh source ObservableSource + * a seventh source {@code ObservableSource} * @param zipper - * a function that, when applied to an item emitted by each of the source ObservableSources, results in - * an item that will be emitted by the resulting ObservableSource - * @return an Observable that emits the zipped results + * a function that, when applied to an item emitted by each of the {@code ObservableSource}s, results in + * an item that will be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull R> Observable zip( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4, @NonNull ObservableSource source5, @NonNull ObservableSource source6, @NonNull ObservableSource source7, @@ -4774,18 +5094,18 @@ public static Observable zip( } /** - * Returns an Observable that emits the results of a specified combiner function applied to combinations of - * eight items emitted, in sequence, by eight other ObservableSources. + * Returns an {@code Observable} that emits the results of a specified combiner function applied to combinations of + * eight items emitted, in sequence, by eight other {@link ObservableSource}s. *

- * + * *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new ObservableSource - * will be the result of the function applied to the first item emitted by each source ObservableSource, the - * second item emitted by the new ObservableSource will be the result of the function applied to the second item - * emitted by each of those ObservableSources, and so forth. + * {@code zip} applies this function in strict sequence, so the first item emitted by the resulting {@code Observable} + * will be the result of the function applied to the first item emitted by each source {@code ObservableSource}, the + * second item emitted by the resulting {@code Observable} will be the result of the function applied to the second item + * emitted by each of those {@code ObservableSource}s, and so forth. *

- * The resulting {@code ObservableSource} returned from {@code zip} will invoke {@link Observer#onNext onNext} - * as many times as the number of {@code onNext} invocations of the source ObservableSource that emits the fewest + * The resulting {@code Observable} returned from {@code zip} will invoke {@link Observer#onNext onNext} + * as many times as the number of {@code onNext} invocations of the {@code ObservableSource} that emits the fewest * items. *

* The operator subscribes to its sources in order they are specified and completes eagerly if @@ -4814,31 +5134,34 @@ public static Observable zip( * @param the value type of the eighth source * @param the zipped result type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * a second source ObservableSource + * a second source {@code ObservableSource} * @param source3 - * a third source ObservableSource + * a third source {@code ObservableSource} * @param source4 - * a fourth source ObservableSource + * a fourth source {@code ObservableSource} * @param source5 - * a fifth source ObservableSource + * a fifth source {@code ObservableSource} * @param source6 - * a sixth source ObservableSource + * a sixth source {@code ObservableSource} * @param source7 - * a seventh source ObservableSource + * a seventh source {@code ObservableSource} * @param source8 - * an eighth source ObservableSource + * an eighth source {@code ObservableSource} * @param zipper - * a function that, when applied to an item emitted by each of the source ObservableSources, results in - * an item that will be emitted by the resulting ObservableSource - * @return an Observable that emits the zipped results + * a function that, when applied to an item emitted by each of the {@code ObservableSource}s, results in + * an item that will be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7}, {@code source8} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull R> Observable zip( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4, @NonNull ObservableSource source5, @NonNull ObservableSource source6, @NonNull ObservableSource source7, @NonNull ObservableSource source8, @@ -4856,18 +5179,18 @@ public static Observable zip( } /** - * Returns an Observable that emits the results of a specified combiner function applied to combinations of - * nine items emitted, in sequence, by nine other ObservableSources. + * Returns an {@code Observable} that emits the results of a specified combiner function applied to combinations of + * nine items emitted, in sequence, by nine other {@link ObservableSource}s. *

- * + * *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new ObservableSource - * will be the result of the function applied to the first item emitted by each source ObservableSource, the - * second item emitted by the new ObservableSource will be the result of the function applied to the second item - * emitted by each of those ObservableSources, and so forth. + * {@code zip} applies this function in strict sequence, so the first item emitted by the resulting {@code Observable} + * will be the result of the function applied to the first item emitted by each source {@code ObservableSource}, the + * second item emitted by the resulting {@code Observable} will be the result of the function applied to the second item + * emitted by each of those {@code ObservableSource}s, and so forth. *

- * The resulting {@code ObservableSource} returned from {@code zip} will invoke {@link Observer#onNext onNext} - * as many times as the number of {@code onNext} invocations of the source ObservableSource that emits the fewest + * The resulting {@code Observable} returned from {@code zip} will invoke {@link Observer#onNext onNext} + * as many times as the number of {@code onNext} invocations of the {@code ObservableSource} that emits the fewest * items. *

* The operator subscribes to its sources in order they are specified and completes eagerly if @@ -4897,33 +5220,36 @@ public static Observable zip( * @param the value type of the ninth source * @param the zipped result type * @param source1 - * the first source ObservableSource + * the first source {@code ObservableSource} * @param source2 - * a second source ObservableSource + * a second source {@code ObservableSource} * @param source3 - * a third source ObservableSource + * a third source {@code ObservableSource} * @param source4 - * a fourth source ObservableSource + * a fourth source {@code ObservableSource} * @param source5 - * a fifth source ObservableSource + * a fifth source {@code ObservableSource} * @param source6 - * a sixth source ObservableSource + * a sixth source {@code ObservableSource} * @param source7 - * a seventh source ObservableSource + * a seventh source {@code ObservableSource} * @param source8 - * an eighth source ObservableSource + * an eighth source {@code ObservableSource} * @param source9 - * a ninth source ObservableSource + * a ninth source {@code ObservableSource} * @param zipper - * a function that, when applied to an item emitted by each of the source ObservableSources, results in - * an item that will be emitted by the resulting ObservableSource - * @return an Observable that emits the zipped results + * a function that, when applied to an item emitted by each of the {@code ObservableSource}s, results in + * an item that will be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4}, {@code source5}, {@code source6}, + * {@code source7}, {@code source8}, {@code source9} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull T9, @NonNull R> Observable zip( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4, @NonNull ObservableSource source5, @NonNull ObservableSource source6, @NonNull ObservableSource source7, @NonNull ObservableSource source8, @NonNull ObservableSource source9, @@ -4942,16 +5268,16 @@ public static Observable zip( } /** - * Returns an Observable that emits the results of a specified combiner function applied to combinations of - * items emitted, in sequence, by an array of other ObservableSources. + * Returns an {@code Observable} that emits the results of a specified combiner function applied to combinations of + * items emitted, in sequence, by an array of other {@link ObservableSource}s. *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new ObservableSource - * will be the result of the function applied to the first item emitted by each of the source ObservableSources; - * the second item emitted by the new ObservableSource will be the result of the function applied to the second - * item emitted by each of those ObservableSources; and so forth. + * {@code zip} applies this function in strict sequence, so the first item emitted by the resulting {@code Observable} + * will be the result of the function applied to the first item emitted by each of the {@code ObservableSource}s; + * the second item emitted by the resulting {@code Observable} will be the result of the function applied to the second + * item emitted by each of those {@code ObservableSource}s; and so forth. *

- * The resulting {@code ObservableSource} returned from {@code zip} will invoke {@code onNext} as many times as - * the number of {@code onNext} invocations of the source ObservableSource that emits the fewest items. + * The resulting {@code Observable} returned from {@code zip} will invoke {@code onNext} as many times as + * the number of {@code onNext} invocations of the {@code ObservableSource} that emits the fewest items. *

* The operator subscribes to its sources in order they are specified and completes eagerly if * one of the sources is shorter than the rest while disposing the other sources. Therefore, it @@ -4968,10 +5294,10 @@ public static Observable zip( *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. * *

- * + * *

*
Scheduler:
*
{@code zipArray} does not operate by default on a particular {@link Scheduler}.
@@ -4980,25 +5306,28 @@ public static Observable zip( * @param the common element type * @param the result type * @param sources - * an array of source ObservableSources + * an array of source {@code ObservableSource}s * @param zipper - * a function that, when applied to an item emitted by each of the source ObservableSources, results in - * an item that will be emitted by the resulting ObservableSource + * a function that, when applied to an item emitted by each of the {@code ObservableSource}s, results in + * an item that will be emitted by the resulting {@code Observable} * @param delayError - * delay errors signalled by any of the source ObservableSource until all ObservableSources terminate + * delay errors signaled by any of the {@code ObservableSource} until all {@code ObservableSource}s terminate * @param bufferSize - * the number of elements to prefetch from each source ObservableSource - * @return an Observable that emits the zipped results + * the number of elements expected from each source {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sources} or {@code zipper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs @NonNull - public static Observable zipArray( + public static <@NonNull T, @NonNull R> Observable zipArray( @NonNull Function zipper, boolean delayError, int bufferSize, @NonNull ObservableSource... sources) { + Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { return empty(); } @@ -5012,19 +5341,19 @@ public static Observable zipArray( // *************************************************************************************************** /** - * Returns a Single that emits a Boolean that indicates whether all of the items emitted by the source - * ObservableSource satisfy a condition. + * Returns a {@link Single} that emits a {@link Boolean} that indicates whether all of the items emitted by the current + * {@code Observable} satisfy a condition. *

- * + * *

*
Scheduler:
*
{@code all} does not operate by default on a particular {@link Scheduler}.
*
* * @param predicate - * a function that evaluates an item and returns a Boolean - * @return a Single that emits {@code true} if all items emitted by the source ObservableSource satisfy the - * predicate; otherwise, {@code false} + * a function that evaluates an item and returns a {@code Boolean} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @see ReactiveX operators documentation: All */ @CheckReturnValue @@ -5036,20 +5365,29 @@ public final Single all(@NonNull Predicate predicate) { } /** - * Mirrors the ObservableSource (current or provided) that first either emits an item or sends a termination + * Mirrors the current {@code Observable} or the other {@link ObservableSource} provided of which the first either emits an item or sends a termination * notification. *

- * + * + *

+ * When the current {@code Observable} signals an item or terminates first, the subscription to the other + * {@code ObservableSource} is disposed. If the other {@code ObservableSource} signals an item or terminates first, + * the subscription to the current {@code Observable} is disposed. *

*
Scheduler:
*
{@code ambWith} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
+ * If the losing {@code ObservableSource} signals an error, the error is routed to the global + * error handler via {@link RxJavaPlugins#onError(Throwable)}. + *
*
* * @param other - * an ObservableSource competing to react first. A subscription to this provided source will occur after + * an {@code ObservableSource} competing to react first. A subscription to this provided source will occur after * subscribing to the current source. - * @return an Observable that emits the same sequence as whichever of the source ObservableSources first - * emitted an item or sent a termination notification + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: Amb */ @CheckReturnValue @@ -5061,13 +5399,13 @@ public final Observable ambWith(@NonNull ObservableSource other) } /** - * Returns a Single that emits {@code true} if any item emitted by the source ObservableSource satisfies a + * Returns a {@link Single} that emits {@code true} if any item emitted by the current {@code Observable} satisfies a * specified condition, otherwise {@code false}. Note: this always emits {@code false} if the - * source ObservableSource is empty. + * current {@code Observable} is empty. *

- * + * *

- * In Rx.Net this is the {@code any} Observer but we renamed it in RxJava to better match Java naming + * In Rx.Net this is the {@code any} {@link Observer} but we renamed it in RxJava to better match Java naming * idioms. *

*
Scheduler:
@@ -5075,9 +5413,9 @@ public final Observable ambWith(@NonNull ObservableSource other) *
* * @param predicate - * the condition to test items emitted by the source ObservableSource - * @return a Single that emits a Boolean that indicates whether any item emitted by the source - * ObservableSource satisfies the {@code predicate} + * the condition to test items emitted by the current {@code Observable} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @see ReactiveX operators documentation: Contains */ @CheckReturnValue @@ -5089,18 +5427,22 @@ public final Single any(@NonNull Predicate predicate) { } /** - * Returns the first item emitted by this {@code Observable}, or throws - * {@code NoSuchElementException} if it emits no items. + * Returns the first item emitted by the current {@code Observable}, or throws + * {@link NoSuchElementException} if it emits no items. *

- * + * *

*
Scheduler:
*
{@code blockingFirst} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If the source signals an error, the operator wraps a checked {@link Exception} + * into {@link RuntimeException} and throws that. Otherwise, {@code RuntimeException}s and + * {@link Error}s are rethrown as they are.
*
* - * @return the first item emitted by this {@code Observable} + * @return the first item emitted by the current {@code Observable} * @throws NoSuchElementException - * if this {@code Observable} emits no items + * if the current {@code Observable} emits no items * @see ReactiveX documentation: First */ @CheckReturnValue @@ -5117,25 +5459,31 @@ public final T blockingFirst() { } /** - * Returns the first item emitted by this {@code Observable}, or a default value if it emits no + * Returns the first item emitted by the current {@code Observable}, or a default value if it emits no * items. *

* *

*
Scheduler:
*
{@code blockingFirst} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If the source signals an error, the operator wraps a checked {@link Exception} + * into {@link RuntimeException} and throws that. Otherwise, {@code RuntimeException}s and + * {@link Error}s are rethrown as they are.
*
* * @param defaultItem - * a default value to return if this {@code Observable} emits no items - * @return the first item emitted by this {@code Observable}, or the default value if it emits no + * a default value to return if the current {@code Observable} emits no items + * @return the first item emitted by the current {@code Observable}, or the default value if it emits no * items + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX documentation: First */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final T blockingFirst(@NonNull T defaultItem) { + Objects.requireNonNull(defaultItem, "defaultItem is null"); BlockingFirstObserver observer = new BlockingFirstObserver<>(); subscribe(observer); T v = observer.blockingGet(); @@ -5143,11 +5491,11 @@ public final T blockingFirst(@NonNull T defaultItem) { } /** - * Consumes the upstream {@code Observable} in a blocking fashion and invokes the given - * {@code Consumer} with each upstream item on the current thread until the + * Consumes the current {@code Observable} in a blocking fashion and invokes the given + * {@link Consumer} with each upstream item on the current thread until the * upstream terminates. *

- * + * *

* Note: the method will only return if the upstream terminates or the current * thread is interrupted. @@ -5165,7 +5513,8 @@ public final T blockingFirst(@NonNull T defaultItem) { *

* * @param onNext - * the {@link Consumer} to invoke for each item emitted by the {@code Observable} + * the {@code Consumer} to invoke for each item emitted by the {@code Observable} + * @throws NullPointerException if {@code onNext} is {@code null} * @throws RuntimeException * if an error occurs * @see ReactiveX documentation: Subscribe @@ -5173,17 +5522,16 @@ public final T blockingFirst(@NonNull T defaultItem) { * @see #blockingForEach(Consumer, int) */ @SchedulerSupport(SchedulerSupport.NONE) - @NonNull public final void blockingForEach(@NonNull Consumer onNext) { blockingForEach(onNext, bufferSize()); } /** - * Consumes the upstream {@code Observable} in a blocking fashion and invokes the given - * {@code Consumer} with each upstream item on the current thread until the + * Consumes the current {@code Observable} in a blocking fashion and invokes the given + * {@link Consumer} with each upstream item on the current thread until the * upstream terminates. *

- * + * *

* Note: the method will only return if the upstream terminates or the current * thread is interrupted. @@ -5201,18 +5549,20 @@ public final void blockingForEach(@NonNull Consumer onNext) { *

* * @param onNext - * the {@link Consumer} to invoke for each item emitted by the {@code Observable} + * the {@code Consumer} to invoke for each item emitted by the {@code Observable} * @param capacityHint * the number of items expected to be buffered (allows reducing buffer reallocations) + * @throws NullPointerException if {@code onNext} is {@code null} + * @throws IllegalArgumentException if {@code capacityHint} is non-positive * @throws RuntimeException - * if an error occurs; {@link Error}s and {@link RuntimeException}s are rethrown - * as they are, checked {@link Exception}s are wrapped into {@code RuntimeException}s + * if an error occurs; {@code Error}s and {@code RuntimeException}s are rethrown + * as they are, checked {@code Exception}s are wrapped into {@code RuntimeException}s * @see ReactiveX documentation: Subscribe * @see #subscribe(Consumer) */ @SchedulerSupport(SchedulerSupport.NONE) - @NonNull public final void blockingForEach(@NonNull Consumer onNext, int capacityHint) { + Objects.requireNonNull(onNext, "onNext is null"); Iterator it = blockingIterable(capacityHint).iterator(); while (it.hasNext()) { try { @@ -5226,15 +5576,17 @@ public final void blockingForEach(@NonNull Consumer onNext, int capac } /** - * Converts this {@code Observable} into an {@link Iterable}. + * Exposes the current {@code Observable} as an {@link Iterable} which, when iterated, + * subscribes to the current {@code Observable} and blocks + * until the current {@code Observable} emits items or terminates. *

- * + * *

*
Scheduler:
*
{@code blockingIterable} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an {@link Iterable} version of this {@code Observable} + * @return the new {@code Iterable} instance * @see ReactiveX documentation: To */ @CheckReturnValue @@ -5245,16 +5597,19 @@ public final Iterable blockingIterable() { } /** - * Converts this {@code Observable} into an {@link Iterable}. + * Exposes the current {@code Observable} as an {@link Iterable} which, when iterated, + * subscribes to the current {@code Observable} and blocks + * until the current {@code Observable} emits items or terminates. *

- * + * *

*
Scheduler:
*
{@code blockingIterable} does not operate by default on a particular {@link Scheduler}.
*
* * @param capacityHint the expected number of items to be buffered - * @return an {@link Iterable} version of this {@code Observable} + * @return the new {@code Iterable} instance + * @throws IllegalArgumentException if {@code capacityHint} is non-positive * @see ReactiveX documentation: To */ @CheckReturnValue @@ -5266,10 +5621,10 @@ public final Iterable blockingIterable(int capacityHint) { } /** - * Returns the last item emitted by this {@code Observable}, or throws - * {@code NoSuchElementException} if this {@code Observable} emits no items. + * Returns the last item emitted by the current {@code Observable}, or throws + * {@link NoSuchElementException} if the current {@code Observable} emits no items. *

- * + * *

*
Scheduler:
*
{@code blockingLast} does not operate by default on a particular {@link Scheduler}.
@@ -5279,9 +5634,9 @@ public final Iterable blockingIterable(int capacityHint) { * {@link Error}s are rethrown as they are.
*
* - * @return the last item emitted by this {@code Observable} + * @return the last item emitted by the current {@code Observable} * @throws NoSuchElementException - * if this {@code Observable} emits no items + * if the current {@code Observable} emits no items * @see ReactiveX documentation: Last */ @CheckReturnValue @@ -5298,10 +5653,10 @@ public final T blockingLast() { } /** - * Returns the last item emitted by this {@code Observable}, or a default value if it emits no + * Returns the last item emitted by the current {@code Observable}, or a default value if it emits no * items. *

- * + * *

*
Scheduler:
*
{@code blockingLast} does not operate by default on a particular {@link Scheduler}.
@@ -5312,15 +5667,17 @@ public final T blockingLast() { *
* * @param defaultItem - * a default value to return if this {@code Observable} emits no items + * a default value to return if the current {@code Observable} emits no items * @return the last item emitted by the {@code Observable}, or the default value if it emits no * items + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX documentation: Last */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final T blockingLast(@NonNull T defaultItem) { + Objects.requireNonNull(defaultItem, "defaultItem is null"); BlockingLastObserver observer = new BlockingLastObserver<>(); subscribe(observer); T v = observer.blockingGet(); @@ -5328,12 +5685,12 @@ public final T blockingLast(@NonNull T defaultItem) { } /** - * Returns an {@link Iterable} that returns the latest item emitted by this {@code Observable}, + * Returns an {@link Iterable} that returns the latest item emitted by the current {@code Observable}, * waiting if necessary for one to become available. *

* *

- * If this {@code Observable} produces items faster than {@code Iterator.next} takes them, + * If the current {@code Observable} produces items faster than {@code Iterator.next} takes them, * {@code onNext} events might be skipped, but {@code onError} or {@code onComplete} events are not. *

* Note also that an {@code onNext} directly followed by {@code onComplete} might hide the {@code onNext} @@ -5343,7 +5700,7 @@ public final T blockingLast(@NonNull T defaultItem) { *

{@code blockingLatest} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an Iterable that always returns the latest item emitted by this {@code Observable} + * @return the new {@code Iterable} instance * @see ReactiveX documentation: First */ @CheckReturnValue @@ -5354,41 +5711,41 @@ public final Iterable blockingLatest() { } /** - * Returns an {@link Iterable} that always returns the item most recently emitted by this + * Returns an {@link Iterable} that always returns the item most recently emitted by the current * {@code Observable}. *

- * + * *

*
Scheduler:
*
{@code blockingMostRecent} does not operate by default on a particular {@link Scheduler}.
*
* - * @param initialValue - * the initial value that the {@link Iterable} sequence will yield if this + * @param initialItem + * the initial value that the {@code Iterable} sequence will yield if the current * {@code Observable} has not yet emitted an item - * @return an {@link Iterable} that on each iteration returns the item that this {@code Observable} - * has most recently emitted + * @return the new {@code Iterable} instance + * @throws NullPointerException if {@code initialItem} is {@code null} * @see ReactiveX documentation: First */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Iterable blockingMostRecent(@NonNull T initialValue) { - return new BlockingObservableMostRecent<>(this, initialValue); + public final Iterable blockingMostRecent(@NonNull T initialItem) { + Objects.requireNonNull(initialItem, "initialItem is null"); + return new BlockingObservableMostRecent<>(this, initialItem); } /** - * Returns an {@link Iterable} that blocks until this {@code Observable} emits another item, then + * Returns an {@link Iterable} that blocks until the current {@code Observable} emits another item, then * returns that item. *

- * + * *

*
Scheduler:
*
{@code blockingNext} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an {@link Iterable} that blocks upon each iteration until this {@code Observable} emits - * a new item, whereupon the Iterable returns that item + * @return the new {@code Iterable} instance * @see ReactiveX documentation: TakeLast */ @CheckReturnValue @@ -5399,10 +5756,10 @@ public final Iterable blockingNext() { } /** - * If this {@code Observable} completes after emitting a single item, return that item, otherwise - * throw a {@code NoSuchElementException}. + * If the current {@code Observable} completes after emitting a single item, return that item, otherwise + * throw a {@link NoSuchElementException}. *

- * + * *

*
Scheduler:
*
{@code blockingSingle} does not operate by default on a particular {@link Scheduler}.
@@ -5412,7 +5769,7 @@ public final Iterable blockingNext() { * {@link Error}s are rethrown as they are.
*
* - * @return the single item emitted by this {@code Observable} + * @return the single item emitted by the current {@code Observable} * @see ReactiveX documentation: First */ @CheckReturnValue @@ -5427,11 +5784,11 @@ public final T blockingSingle() { } /** - * If this {@code Observable} completes after emitting a single item, return that item; if it emits - * more than one item, throw an {@code IllegalArgumentException}; if it emits no items, return a default + * If the current {@code Observable} completes after emitting a single item, return that item; if it emits + * more than one item, throw an {@link IllegalArgumentException}; if it emits no items, return a default * value. *

- * + * *

*
Scheduler:
*
{@code blockingSingle} does not operate by default on a particular {@link Scheduler}.
@@ -5442,9 +5799,10 @@ public final T blockingSingle() { *
* * @param defaultItem - * a default value to return if this {@code Observable} emits no items - * @return the single item emitted by this {@code Observable}, or the default value if it emits no + * a default value to return if the current {@code Observable} emits no items + * @return the single item emitted by the current {@code Observable}, or the default value if it emits no * items + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX documentation: First */ @CheckReturnValue @@ -5455,13 +5813,13 @@ public final T blockingSingle(@NonNull T defaultItem) { } /** - * Returns a {@link Future} representing the only value emitted by this {@code Observable}. + * Returns a {@link Future} representing the only value emitted by the current {@code Observable}. *

- * + * *

- * If the {@link Observable} emits more than one item, {@link java.util.concurrent.Future} will receive an - * {@link java.lang.IndexOutOfBoundsException}. If the {@link Observable} is empty, {@link java.util.concurrent.Future} - * will receive an {@link java.util.NoSuchElementException}. The {@code Observable} source has to terminate in order + * If the {@code Observable} emits more than one item, {@code Future} will receive an + * {@link IndexOutOfBoundsException}. If the {@code Observable} is empty, {@code Future} + * will receive an {@link NoSuchElementException}. The {@code Observable} source has to terminate in order * for the returned {@code Future} to terminate as well. *

* If the {@code Observable} may emit more than one item, use {@code Observable.toList().toFuture()}. @@ -5470,8 +5828,9 @@ public final T blockingSingle(@NonNull T defaultItem) { *

{@code toFuture} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@link Future} that expects a single item to be emitted by this {@code Observable} + * @return the new {@code Future} instance * @see ReactiveX documentation: To + * @see #singleOrErrorStage() */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -5481,7 +5840,7 @@ public final Future toFuture() { } /** - * Runs the source observable to a terminal event, ignoring any values and rethrowing any exception. + * Runs the current {@code Observable} to a terminal event, ignoring any values and rethrowing any exception. *

* *

@@ -5505,11 +5864,11 @@ public final void blockingSubscribe() { /** * Subscribes to the source and calls the given callbacks on the current thread. *

- * + * *

* If the {@code Observable} emits an error, it is wrapped into an - * {@link io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException OnErrorNotImplementedException} - * and routed to the RxJavaPlugins.onError handler. + * {@link OnErrorNotImplementedException} + * and routed to the {@link RxJavaPlugins#onError(Throwable)} handler. * Using the overloads {@link #blockingSubscribe(Consumer, Consumer)} * or {@link #blockingSubscribe(Consumer, Consumer, Action)} instead is recommended. *

@@ -5521,6 +5880,7 @@ public final void blockingSubscribe() { *

{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
*
* @param onNext the callback action for each source value + * @throws NullPointerException if {@code onNext} is {@code null} * @since 2.0 * @see #blockingSubscribe(Consumer, Consumer) * @see #blockingSubscribe(Consumer, Consumer, Action) @@ -5533,7 +5893,7 @@ public final void blockingSubscribe(@NonNull Consumer onNext) { /** * Subscribes to the source and calls the given callbacks on the current thread. *

- * + * *

* Note that calling this method will block the caller thread until the upstream terminates * normally or with an error. Therefore, calling this method from special threads such as the @@ -5544,6 +5904,7 @@ public final void blockingSubscribe(@NonNull Consumer onNext) { *

* @param onNext the callback action for each source value * @param onError the callback action for an error event + * @throws NullPointerException if {@code onNext} or {@code onError} is {@code null} * @since 2.0 * @see #blockingSubscribe(Consumer, Consumer, Action) */ @@ -5567,6 +5928,7 @@ public final void blockingSubscribe(@NonNull Consumer onNext, @NonNul * @param onNext the callback action for each source value * @param onError the callback action for an error event * @param onComplete the callback action for the completion event. + * @throws NullPointerException if {@code onNext}, {@code onError} or {@code onComplete} is {@code null} * @since 2.0 */ @SchedulerSupport(SchedulerSupport.NONE) @@ -5588,21 +5950,23 @@ public final void blockingSubscribe(@NonNull Consumer onNext, @NonNul *
* The a dispose() call is composed through. * @param observer the {@code Observer} instance to forward events and calls to in the current thread + * @throws NullPointerException if {@code observer} is {@code null} * @since 2.0 */ @SchedulerSupport(SchedulerSupport.NONE) public final void blockingSubscribe(@NonNull Observer observer) { + Objects.requireNonNull(observer, "observer is null"); ObservableBlockingSubscribe.subscribe(this, observer); } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping buffers, each containing {@code count} items. When the source - * ObservableSource completes, the resulting ObservableSource emits the current buffer and propagates the notification - * from the source ObservableSource. Note that if the source ObservableSource issues an onError notification + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping buffers, each containing {@code count} items. When the current + * {@code Observable} completes, the resulting {@code Observable} emits the current buffer and propagates the notification + * from the current {@code Observable}. Note that if the current {@code Observable} issues an {@code onError} notification * the event is passed on immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Scheduler:
*
This version of {@code buffer} does not operate by default on a particular {@link Scheduler}.
@@ -5610,8 +5974,8 @@ public final void blockingSubscribe(@NonNull Observer observer) { * * @param count * the maximum number of items in each buffer before it should be emitted - * @return an Observable that emits connected, non-overlapping buffers, each containing at most - * {@code count} items from the source ObservableSource + * @return the new {@code Observable} instance + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -5622,13 +5986,13 @@ public final void blockingSubscribe(@NonNull Observer observer) { } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource emits buffers every {@code skip} items, each containing {@code count} items. When the source - * ObservableSource completes, the resulting ObservableSource emits the current buffer and propagates the notification - * from the source ObservableSource. Note that if the source ObservableSource issues an onError notification + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits buffers every {@code skip} items, each containing {@code count} items. When the current + * {@code Observable} completes, the resulting {@code Observable} emits the current buffer and propagates the notification + * from the current {@code Observable}. Note that if the current {@code Observable} issues an {@code onError} notification * the event is passed on immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Scheduler:
*
This version of {@code buffer} does not operate by default on a particular {@link Scheduler}.
@@ -5637,11 +6001,11 @@ public final void blockingSubscribe(@NonNull Observer observer) { * @param count * the maximum size of each buffer before it should be emitted * @param skip - * how many items emitted by the source ObservableSource should be skipped before starting a new + * how many items emitted by the current {@code Observable} should be skipped before starting a new * buffer. Note that when {@code skip} and {@code count} are equal, this is the same operation as * {@link #buffer(int)}. - * @return an Observable that emits buffers for every {@code skip} item from the source ObservableSource and - * containing at most {@code count} items + * @return the new {@code Observable} instance + * @throws IllegalArgumentException if {@code count} or {@code skip} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -5652,13 +6016,13 @@ public final void blockingSubscribe(@NonNull Observer observer) { } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource emits buffers every {@code skip} items, each containing {@code count} items. When the source - * ObservableSource completes, the resulting ObservableSource emits the current buffer and propagates the notification - * from the source ObservableSource. Note that if the source ObservableSource issues an onError notification + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits buffers every {@code skip} items, each containing {@code count} items. When the current + * {@code Observable} completes, the resulting {@code Observable} emits the current buffer and propagates the notification + * from the current {@code Observable}. Note that if the current {@code Observable} issues an {@code onError} notification * the event is passed on immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Scheduler:
*
This version of {@code buffer} does not operate by default on a particular {@link Scheduler}.
@@ -5668,20 +6032,21 @@ public final void blockingSubscribe(@NonNull Observer observer) { * @param count * the maximum size of each buffer before it should be emitted * @param skip - * how many items emitted by the source ObservableSource should be skipped before starting a new + * how many items emitted by the current {@code Observable} should be skipped before starting a new * buffer. Note that when {@code skip} and {@code count} are equal, this is the same operation as * {@link #buffer(int)}. * @param bufferSupplier * a factory function that returns an instance of the collection subclass to be used and returned * as the buffer - * @return an Observable that emits buffers for every {@code skip} item from the source ObservableSource and - * containing at most {@code count} items + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code bufferSupplier} is {@code null} + * @throws IllegalArgumentException if {@code count} or {@code skip} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final > Observable buffer(int count, int skip, @NonNull Supplier bufferSupplier) { + public final <@NonNull U extends Collection> Observable buffer(int count, int skip, @NonNull Supplier bufferSupplier) { ObjectHelper.verifyPositive(count, "count"); ObjectHelper.verifyPositive(skip, "skip"); Objects.requireNonNull(bufferSupplier, "bufferSupplier is null"); @@ -5689,13 +6054,13 @@ public final > Observable buffer(int count, i } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping buffers, each containing {@code count} items. When the source - * ObservableSource completes, the resulting ObservableSource emits the current buffer and propagates the notification - * from the source ObservableSource. Note that if the source ObservableSource issues an onError notification + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping buffers, each containing {@code count} items. When the current + * {@code Observable} completes, the resulting {@code Observable} emits the current buffer and propagates the notification + * from the current {@code Observable}. Note that if the current {@code Observable} issues an {@code onError} notification * the event is passed on immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Scheduler:
*
This version of {@code buffer} does not operate by default on a particular {@link Scheduler}.
@@ -5707,8 +6072,9 @@ public final > Observable buffer(int count, i * @param bufferSupplier * a factory function that returns an instance of the collection subclass to be used and returned * as the buffer - * @return an Observable that emits connected, non-overlapping buffers, each containing at most - * {@code count} items from the source ObservableSource + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code bufferSupplier} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -5719,14 +6085,14 @@ public final > Observable buffer(int count, i } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource starts a new buffer periodically, as determined by the {@code timeskip} argument. It emits - * each buffer after a fixed timespan, specified by the {@code timespan} argument. When the source - * ObservableSource completes, the resulting ObservableSource emits the current buffer and propagates the notification - * from the source ObservableSource. Note that if the source ObservableSource issues an onError notification + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} starts a new buffer periodically, as determined by the {@code timeskip} argument. It emits + * each buffer after a fixed timespan, specified by the {@code timespan} argument. When the current + * {@code Observable} completes, the resulting {@code Observable} emits the current buffer and propagates the notification + * from the current {@code Observable}. Note that if the current {@code Observable} issues an {@code onError} notification * the event is passed on immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Scheduler:
*
This version of {@code buffer} operates by default on the {@code computation} {@link Scheduler}.
@@ -5738,8 +6104,8 @@ public final > Observable buffer(int count, i * the period of time after which a new buffer will be created * @param unit * the unit of time that applies to the {@code timespan} and {@code timeskip} arguments - * @return an Observable that emits new buffers of items emitted by the source ObservableSource periodically after - * a fixed timespan has elapsed + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -5750,15 +6116,15 @@ public final > Observable buffer(int count, i } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource starts a new buffer periodically, as determined by the {@code timeskip} argument, and on the + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} starts a new buffer periodically, as determined by the {@code timeskip} argument, and on the * specified {@code scheduler}. It emits each buffer after a fixed timespan, specified by the - * {@code timespan} argument. When the source ObservableSource completes, the resulting ObservableSource emits the - * current buffer and propagates the notification from the source ObservableSource. Note that if the source - * ObservableSource issues an onError notification the event is passed on immediately without first emitting the + * {@code timespan} argument. When the current {@code Observable} completes, the resulting {@code Observable} emits the + * current buffer and propagates the notification from the current {@code Observable}. Note that if the current + * {@code Observable} issues an {@code onError} notification the event is passed on immediately without first emitting the * buffer it is in the process of assembling. *

- * + * *

*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
@@ -5771,9 +6137,9 @@ public final > Observable buffer(int count, i * @param unit * the unit of time that applies to the {@code timespan} and {@code timeskip} arguments * @param scheduler - * the {@link Scheduler} to use when determining the end and start of a buffer - * @return an Observable that emits new buffers of items emitted by the source ObservableSource periodically after - * a fixed timespan has elapsed + * the {@code Scheduler} to use when determining the end and start of a buffer + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -5784,15 +6150,15 @@ public final > Observable buffer(int count, i } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource starts a new buffer periodically, as determined by the {@code timeskip} argument, and on the + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} starts a new buffer periodically, as determined by the {@code timeskip} argument, and on the * specified {@code scheduler}. It emits each buffer after a fixed timespan, specified by the - * {@code timespan} argument. When the source ObservableSource completes, the resulting ObservableSource emits the - * current buffer and propagates the notification from the source ObservableSource. Note that if the source - * ObservableSource issues an onError notification the event is passed on immediately without first emitting the + * {@code timespan} argument. When the current {@code Observable} completes, the resulting {@code Observable} emits the + * current buffer and propagates the notification from the current {@code Observable}. Note that if the current + * {@code Observable} issues an {@code onError} notification the event is passed on immediately without first emitting the * buffer it is in the process of assembling. *

- * + * *

*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
@@ -5806,12 +6172,12 @@ public final > Observable buffer(int count, i * @param unit * the unit of time that applies to the {@code timespan} and {@code timeskip} arguments * @param scheduler - * the {@link Scheduler} to use when determining the end and start of a buffer + * the {@code Scheduler} to use when determining the end and start of a buffer * @param bufferSupplier * a factory function that returns an instance of the collection subclass to be used and returned * as the buffer - * @return an Observable that emits new buffers of items emitted by the source ObservableSource periodically after - * a fixed timespan has elapsed + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code bufferSupplier} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -5825,14 +6191,14 @@ public final > Observable buffer(int count, i } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping buffers, each of a fixed duration specified by the - * {@code timespan} argument. When the source ObservableSource completes, the resulting ObservableSource emits the - * current buffer and propagates the notification from the source ObservableSource. Note that if the source - * ObservableSource issues an onError notification the event is passed on immediately without first emitting the + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping buffers, each of a fixed duration specified by the + * {@code timespan} argument. When the current {@code Observable} completes, the resulting {@code Observable} emits the + * current buffer and propagates the notification from the current {@code Observable}. Note that if the current + * {@code Observable} issues an {@code onError} notification the event is passed on immediately without first emitting the * buffer it is in the process of assembling. *

- * + * *

*
Scheduler:
*
This version of {@code buffer} operates by default on the {@code computation} {@link Scheduler}.
@@ -5843,8 +6209,8 @@ public final > Observable buffer(int count, i * buffer * @param unit * the unit of time that applies to the {@code timespan} argument - * @return an Observable that emits connected, non-overlapping buffers of items emitted by the source - * ObservableSource within a fixed duration + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -5855,15 +6221,15 @@ public final > Observable buffer(int count, i } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping buffers, each of a fixed duration specified by the + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping buffers, each of a fixed duration specified by the * {@code timespan} argument or a maximum size specified by the {@code count} argument (whichever is reached - * first). When the source ObservableSource completes, the resulting ObservableSource emits the current buffer and - * propagates the notification from the source ObservableSource. Note that if the source ObservableSource issues an - * onError notification the event is passed on immediately without first emitting the buffer it is in the process of + * first). When the current {@code Observable} completes, the resulting {@code Observable} emits the current buffer and + * propagates the notification from the current {@code Observable}. Note that if the current {@code Observable} issues an + * {@code onError} notification the event is passed on immediately without first emitting the buffer it is in the process of * assembling. *

- * + * *

*
Scheduler:
*
This version of {@code buffer} operates by default on the {@code computation} {@link Scheduler}.
@@ -5876,9 +6242,9 @@ public final > Observable buffer(int count, i * the unit of time which applies to the {@code timespan} argument * @param count * the maximum size of each buffer before it is emitted - * @return an Observable that emits connected, non-overlapping buffers of items emitted by the source - * ObservableSource, after a fixed duration or when the buffer reaches maximum capacity (whichever occurs - * first) + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -5889,15 +6255,15 @@ public final > Observable buffer(int count, i } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping buffers, each of a fixed duration specified by the + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping buffers, each of a fixed duration specified by the * {@code timespan} argument as measured on the specified {@code scheduler}, or a maximum size specified by - * the {@code count} argument (whichever is reached first). When the source ObservableSource completes, the resulting - * ObservableSource emits the current buffer and propagates the notification from the source ObservableSource. Note - * that if the source ObservableSource issues an onError notification the event is passed on immediately without + * the {@code count} argument (whichever is reached first). When the current {@code Observable} completes, the resulting + * {@code Observable} emits the current buffer and propagates the notification from the current {@code Observable}. Note + * that if the current {@code Observable} issues an {@code onError} notification the event is passed on immediately without * first emitting the buffer it is in the process of assembling. *

- * + * *

*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
@@ -5909,12 +6275,12 @@ public final > Observable buffer(int count, i * @param unit * the unit of time which applies to the {@code timespan} argument * @param scheduler - * the {@link Scheduler} to use when determining the end and start of a buffer + * the {@code Scheduler} to use when determining the end and start of a buffer * @param count * the maximum size of each buffer before it is emitted - * @return an Observable that emits connected, non-overlapping buffers of items emitted by the source - * ObservableSource after a fixed duration or when the buffer reaches maximum capacity (whichever occurs - * first) + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -5925,15 +6291,15 @@ public final > Observable buffer(int count, i } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping buffers, each of a fixed duration specified by the + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping buffers, each of a fixed duration specified by the * {@code timespan} argument as measured on the specified {@code scheduler}, or a maximum size specified by - * the {@code count} argument (whichever is reached first). When the source ObservableSource completes, the resulting - * ObservableSource emits the current buffer and propagates the notification from the source ObservableSource. Note - * that if the source ObservableSource issues an onError notification the event is passed on immediately without + * the {@code count} argument (whichever is reached first). When the current {@code Observable} completes, the resulting + * {@code Observable} emits the current buffer and propagates the notification from the current {@code Observable}. Note + * that if the current {@code Observable} issues an {@code onError} notification the event is passed on immediately without * first emitting the buffer it is in the process of assembling. *

- * + * *

*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
@@ -5946,17 +6312,17 @@ public final > Observable buffer(int count, i * @param unit * the unit of time which applies to the {@code timespan} argument * @param scheduler - * the {@link Scheduler} to use when determining the end and start of a buffer + * the {@code Scheduler} to use when determining the end and start of a buffer * @param count * the maximum size of each buffer before it is emitted * @param bufferSupplier * a factory function that returns an instance of the collection subclass to be used and returned * as the buffer - * @param restartTimerOnMaxSize if true the time window is restarted when the max capacity of the current buffer + * @param restartTimerOnMaxSize if {@code true}, the time window is restarted when the max capacity of the current buffer * is reached - * @return an Observable that emits connected, non-overlapping buffers of items emitted by the source - * ObservableSource after a fixed duration or when the buffer reaches maximum capacity (whichever occurs - * first) + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code bufferSupplier} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -5975,14 +6341,14 @@ public final > Observable buffer(int count, i } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping buffers, each of a fixed duration specified by the - * {@code timespan} argument and on the specified {@code scheduler}. When the source ObservableSource completes, - * the resulting ObservableSource emits the current buffer and propagates the notification from the source - * ObservableSource. Note that if the source ObservableSource issues an onError notification the event is passed on + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping buffers, each of a fixed duration specified by the + * {@code timespan} argument and on the specified {@code scheduler}. When the current {@code Observable} completes, + * the resulting {@code Observable} emits the current buffer and propagates the notification from the current + * {@code Observable}. Note that if the current {@code Observable} issues an {@code onError} notification the event is passed on * immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
@@ -5994,9 +6360,9 @@ public final > Observable buffer(int count, i * @param unit * the unit of time which applies to the {@code timespan} argument * @param scheduler - * the {@link Scheduler} to use when determining the end and start of a buffer - * @return an Observable that emits connected, non-overlapping buffers of items emitted by the source - * ObservableSource within a fixed duration + * the {@code Scheduler} to use when determining the end and start of a buffer + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @@ -6007,70 +6373,70 @@ public final > Observable buffer(int count, i } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource emits buffers that it creates when the specified {@code openingIndicator} ObservableSource emits an - * item, and closes when the ObservableSource returned from {@code closingIndicator} emits an item. If any of the - * source ObservableSource, {@code openingIndicator} or {@code closingIndicator} issues an onError notification the + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits buffers that it creates when the specified {@code openingIndicator} {@link ObservableSource} emits an + * item, and closes when the {@code ObservableSource} returned from {@code closingIndicator} emits an item. If any of the + * current {@code Observable}, {@code openingIndicator} or {@code closingIndicator} issues an {@code onError} notification the * event is passed on immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Scheduler:
*
This version of {@code buffer} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the element type of the buffer-opening ObservableSource - * @param the element type of the individual buffer-closing ObservableSources + * @param the element type of the buffer-opening {@code ObservableSource} + * @param the element type of the individual buffer-closing {@code ObservableSource}s * @param openingIndicator - * the ObservableSource that, when it emits an item, causes a new buffer to be created + * the {@code ObservableSource} that, when it emits an item, causes a new buffer to be created * @param closingIndicator - * the {@link Function} that is used to produce an ObservableSource for every buffer created. When this - * ObservableSource emits an item, the associated buffer is emitted. - * @return an Observable that emits buffers, containing items from the source ObservableSource, that are created - * and closed when the specified ObservableSources emit items + * the {@link Function} that is used to produce an {@code ObservableSource} for every buffer created. When this indicator + * {@code ObservableSource} emits an item, the associated buffer is emitted. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code openingIndicator} or {@code closingIndicator} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable<@NonNull List> buffer( + public final <@NonNull TOpening, @NonNull TClosing> Observable<@NonNull List> buffer( @NonNull ObservableSource openingIndicator, @NonNull Function> closingIndicator) { return buffer(openingIndicator, closingIndicator, ArrayListSupplier.asSupplier()); } /** - * Returns an Observable that emits buffers of items it collects from the source ObservableSource. The resulting - * ObservableSource emits buffers that it creates when the specified {@code openingIndicator} ObservableSource emits an - * item, and closes when the ObservableSource returned from {@code closingIndicator} emits an item. If any of the - * source ObservableSource, {@code openingIndicator} or {@code closingIndicator} issues an onError notification the + * Returns an {@code Observable} that emits buffers of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits buffers that it creates when the specified {@code openingIndicator} {@link ObservableSource} emits an + * item, and closes when the {@code ObservableSource} returned from {@code closingIndicator} emits an item. If any of the + * current {@code Observable}, {@code openingIndicator} or {@code closingIndicator} issues an {@code onError} notification the * event is passed on immediately without first emitting the buffer it is in the process of assembling. *

- * + * *

*
Scheduler:
*
This version of {@code buffer} does not operate by default on a particular {@link Scheduler}.
*
* * @param the collection subclass type to buffer into - * @param the element type of the buffer-opening ObservableSource - * @param the element type of the individual buffer-closing ObservableSources + * @param the element type of the buffer-opening {@code ObservableSource} + * @param the element type of the individual buffer-closing {@code ObservableSource}s * @param openingIndicator - * the ObservableSource that, when it emits an item, causes a new buffer to be created + * the {@code ObservableSource} that, when it emits an item, causes a new buffer to be created * @param closingIndicator - * the {@link Function} that is used to produce an ObservableSource for every buffer created. When this - * ObservableSource emits an item, the associated buffer is emitted. + * the {@link Function} that is used to produce an {@code ObservableSource} for every buffer created. When this indicator + * {@code ObservableSource} emits an item, the associated buffer is emitted. * @param bufferSupplier * a factory function that returns an instance of the collection subclass to be used and returned * as the buffer - * @return an Observable that emits buffers, containing items from the source ObservableSource, that are created - * and closed when the specified ObservableSources emit items + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code openingIndicator}, {@code closingIndicator} or {@code bufferSupplier} is {@code null} * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final > Observable buffer( + public final <@NonNull TOpening, @NonNull TClosing, @NonNull U extends Collection> Observable buffer( @NonNull ObservableSource openingIndicator, @NonNull Function> closingIndicator, @NonNull Supplier bufferSupplier) { @@ -6081,14 +6447,14 @@ public final > Observable buffer(int count, i } /** - * Returns an Observable that emits non-overlapping buffered items from the source ObservableSource each time the - * specified boundary ObservableSource emits an item. + * Returns an {@code Observable} that emits non-overlapping buffered items from the current {@code Observable} each time the + * specified boundary {@link ObservableSource} emits an item. *

- * + * *

- * Completion of either the source or the boundary ObservableSource causes the returned ObservableSource to emit the - * latest buffer and complete. If either the source ObservableSource or the boundary ObservableSource issues an - * onError notification the event is passed on immediately without first emitting the buffer it is in the process of + * Completion of either the source or the boundary {@code ObservableSource} causes the returned {@code ObservableSource} to emit the + * latest buffer and complete. If either the current {@code Observable} or the boundary {@code ObservableSource} issues an + * {@code onError} notification the event is passed on immediately without first emitting the buffer it is in the process of * assembling. *

*
Scheduler:
@@ -6097,29 +6463,29 @@ public final > Observable buffer(int count, i * * @param * the boundary value type (ignored) - * @param boundary - * the boundary ObservableSource - * @return an Observable that emits buffered items from the source ObservableSource when the boundary ObservableSource - * emits an item + * @param boundaryIndicator + * the boundary {@code ObservableSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code boundaryIndicator} is {@code null} * @see #buffer(ObservableSource, int) * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable<@NonNull List> buffer(@NonNull ObservableSource boundary) { - return buffer(boundary, ArrayListSupplier.asSupplier()); + public final <@NonNull B> Observable<@NonNull List> buffer(@NonNull ObservableSource boundaryIndicator) { + return buffer(boundaryIndicator, ArrayListSupplier.asSupplier()); } /** - * Returns an Observable that emits non-overlapping buffered items from the source ObservableSource each time the - * specified boundary ObservableSource emits an item. + * Returns an {@code Observable} that emits non-overlapping buffered items from the current {@code Observable} each time the + * specified boundary {@link ObservableSource} emits an item. *

- * + * *

- * Completion of either the source or the boundary ObservableSource causes the returned ObservableSource to emit the - * latest buffer and complete. If either the source ObservableSource or the boundary ObservableSource issues an - * onError notification the event is passed on immediately without first emitting the buffer it is in the process of + * Completion of either the source or the boundary {@code ObservableSource} causes the returned {@code ObservableSource} to emit the + * latest buffer and complete. If either the current {@code Observable} or the boundary {@code ObservableSource} issues an + * {@code onError} notification the event is passed on immediately without first emitting the buffer it is in the process of * assembling. *

*
Scheduler:
@@ -6128,32 +6494,33 @@ public final > Observable buffer(int count, i * * @param * the boundary value type (ignored) - * @param boundary - * the boundary ObservableSource + * @param boundaryIndicator + * the boundary {@code ObservableSource} * @param initialCapacity * the initial capacity of each buffer chunk - * @return an Observable that emits buffered items from the source ObservableSource when the boundary ObservableSource - * emits an item + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Buffer + * @throws NullPointerException if {@code boundaryIndicator} is {@code null} + * @throws IllegalArgumentException if {@code initialCapacity} is non-positive * @see #buffer(ObservableSource) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable<@NonNull List> buffer(@NonNull ObservableSource boundary, int initialCapacity) { + public final <@NonNull B> Observable<@NonNull List> buffer(@NonNull ObservableSource boundaryIndicator, int initialCapacity) { ObjectHelper.verifyPositive(initialCapacity, "initialCapacity"); - return buffer(boundary, Functions.createArrayList(initialCapacity)); + return buffer(boundaryIndicator, Functions.createArrayList(initialCapacity)); } /** - * Returns an Observable that emits non-overlapping buffered items from the source ObservableSource each time the - * specified boundary ObservableSource emits an item. + * Returns an {@code Observable} that emits non-overlapping buffered items from the current {@code Observable} each time the + * specified boundary {@link ObservableSource} emits an item. *

- * + * *

- * Completion of either the source or the boundary ObservableSource causes the returned ObservableSource to emit the - * latest buffer and complete. If either the source ObservableSource or the boundary ObservableSource issues an - * onError notification the event is passed on immediately without first emitting the buffer it is in the process of + * Completion of either the source or the boundary {@code ObservableSource} causes the returned {@code ObservableSource} to emit the + * latest buffer and complete. If either the current {@code Observable} or the boundary {@code ObservableSource} issues an + * {@code onError} notification the event is passed on immediately without first emitting the buffer it is in the process of * assembling. *

*
Scheduler:
@@ -6163,43 +6530,43 @@ public final > Observable buffer(int count, i * @param the collection subclass type to buffer into * @param * the boundary value type (ignored) - * @param boundary - * the boundary ObservableSource + * @param boundaryIndicator + * the boundary {@code ObservableSource} * @param bufferSupplier * a factory function that returns an instance of the collection subclass to be used and returned * as the buffer - * @return an Observable that emits buffered items from the source ObservableSource when the boundary ObservableSource - * emits an item + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code boundaryIndicator} or {@code bufferSupplier} is {@code null} * @see #buffer(ObservableSource, int) * @see ReactiveX operators documentation: Buffer */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final > Observable buffer(@NonNull ObservableSource boundary, @NonNull Supplier bufferSupplier) { - Objects.requireNonNull(boundary, "boundary is null"); + public final <@NonNull B, @NonNull U extends Collection> Observable buffer(@NonNull ObservableSource boundaryIndicator, @NonNull Supplier bufferSupplier) { + Objects.requireNonNull(boundaryIndicator, "boundaryIndicator is null"); Objects.requireNonNull(bufferSupplier, "bufferSupplier is null"); - return RxJavaPlugins.onAssembly(new ObservableBufferExactBoundary<>(this, boundary, bufferSupplier)); + return RxJavaPlugins.onAssembly(new ObservableBufferExactBoundary<>(this, boundaryIndicator, bufferSupplier)); } /** - * Returns an Observable that subscribes to this ObservableSource lazily, caches all of its events - * and replays them, in the same order as received, to all the downstream subscribers. + * Returns an {@code Observable} that subscribes to the current {@code Observable} lazily, caches all of its events + * and replays them, in the same order as received, to all the downstream observers. *

- * + * *

- * This is useful when you want an ObservableSource to cache responses and you can't control the + * This is useful when you want an {@code Observable} to cache responses and you can't control the * subscribe/dispose behavior of all the {@link Observer}s. *

- * The operator subscribes only when the first downstream subscriber subscribes and maintains - * a single subscription towards this ObservableSource. In contrast, the operator family of {@link #replay()} + * The operator subscribes only when the first downstream observer subscribes and maintains + * a single subscription towards the current {@code Observable}. In contrast, the operator family of {@link #replay()} * that return a {@link ConnectableObservable} require an explicit call to {@link ConnectableObservable#connect()}. *

* Note: You sacrifice the ability to dispose the origin when you use the {@code cache} - * Observer so be careful not to use this Observer on ObservableSources that emit an infinite or very large number + * operator so be careful not to use this operator on {@code Observable}s that emit an infinite or very large number * of items that will use up memory. - * A possible workaround is to apply `takeUntil` with a predicate or - * another source before (and perhaps after) the application of cache(). + * A possible workaround is to apply {@code takeUntil} with a predicate or + * another source before (and perhaps after) the application of {@code cache()}. *


      * AtomicBoolean shouldStop = new AtomicBoolean();
      *
@@ -6226,9 +6593,10 @@ public final > Observable buffer(int count, i
      *  
{@code cache} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an Observable that, when first subscribed to, caches all of its items and notifications for the - * benefit of subsequent subscribers + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Replay + * @see #takeUntil(Predicate) + * @see #takeUntil(ObservableSource) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -6238,23 +6606,23 @@ public final Observable cache() { } /** - * Returns an Observable that subscribes to this ObservableSource lazily, caches all of its events - * and replays them, in the same order as received, to all the downstream subscribers. + * Returns an {@code Observable} that subscribes to the current {@code Observable} lazily, caches all of its events + * and replays them, in the same order as received, to all the downstream observers. *

- * + * *

- * This is useful when you want an ObservableSource to cache responses and you can't control the + * This is useful when you want an {@code Observable} to cache responses and you can't control the * subscribe/dispose behavior of all the {@link Observer}s. *

- * The operator subscribes only when the first downstream subscriber subscribes and maintains - * a single subscription towards this ObservableSource. In contrast, the operator family of {@link #replay()} + * The operator subscribes only when the first downstream observer subscribes and maintains + * a single subscription towards the current {@code Observable}. In contrast, the operator family of {@link #replay()} * that return a {@link ConnectableObservable} require an explicit call to {@link ConnectableObservable#connect()}. *

* Note: You sacrifice the ability to dispose the origin when you use the {@code cache} - * Observer so be careful not to use this Observer on ObservableSources that emit an infinite or very large number + * operator so be careful not to use this operator on {@code Observable}s that emit an infinite or very large number * of items that will use up memory. * A possible workaround is to apply `takeUntil` with a predicate or - * another source before (and perhaps after) the application of cache(). + * another source before (and perhaps after) the application of {@code cache()}. *


      * AtomicBoolean shouldStop = new AtomicBoolean();
      *
@@ -6285,9 +6653,11 @@ public final Observable cache() {
      * {@link #replay(int)} in combination with {@link ConnectableObservable#autoConnect()} or similar.
      *
      * @param initialCapacity hint for number of items to cache (for optimizing underlying data structure)
-     * @return an Observable that, when first subscribed to, caches all of its items and notifications for the
-     *         benefit of subsequent subscribers
+     * @return the new {@code Observable} instance
+     * @throws IllegalArgumentException if {@code initialCapacity} is non-positive
      * @see ReactiveX operators documentation: Replay
+     * @see #takeUntil(Predicate)
+     * @see #takeUntil(ObservableSource)
      */
     @CheckReturnValue
     @SchedulerSupport(SchedulerSupport.NONE)
@@ -6298,10 +6668,12 @@ public final Observable cacheWithInitialCapacity(int initialCapacity) {
     }
 
     /**
-     * Returns an Observable that emits the items emitted by the source ObservableSource, converted to the specified
-     * type.
+     * Returns an {@code Observable} that emits the upstream items while
+     * they can be cast via {@link Class#cast(Object)} until the upstream terminates,
+     * or until the upstream signals an item which can't be cast,
+     * resulting in a {@link ClassCastException} to be signaled to the downstream.
      * 

- * + * *

*
Scheduler:
*
{@code cast} does not operate by default on a particular {@link Scheduler}.
@@ -6309,122 +6681,122 @@ public final Observable cacheWithInitialCapacity(int initialCapacity) { * * @param the output value type cast to * @param clazz - * the target class type that {@code cast} will cast the items emitted by the source ObservableSource - * into before emitting them from the resulting ObservableSource - * @return an Observable that emits each item from the source ObservableSource after converting it to the - * specified type + * the target class to use to try and cast the upstream items into + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code clazz} is {@code null} * @see ReactiveX operators documentation: Map */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable cast(@NonNull Class clazz) { + public final <@NonNull U> Observable cast(@NonNull Class clazz) { Objects.requireNonNull(clazz, "clazz is null"); return map(Functions.castFunction(clazz)); } /** - * Collects items emitted by the finite source ObservableSource into a single mutable data structure and returns - * a Single that emits this structure. + * Collects items emitted by the finite source {@code Observable} into a single mutable data structure and returns + * a {@link Single} that emits this structure. *

- * + * *

* This is a simplified version of {@code reduce} that does not need to return the state on each pass. *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulator object to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code collect} does not operate by default on a particular {@link Scheduler}.
*
* * @param the accumulator and output type - * @param initialValueSupplier + * @param initialItemSupplier * the mutable data structure that will collect the items * @param collector - * a function that accepts the {@code state} and an emitted item, and modifies {@code state} + * a function that accepts the {@code state} and an emitted item, and modifies the accumulator accordingly * accordingly - * @return a Single that emits the result of collecting the values emitted by the source ObservableSource - * into a single mutable data structure + * @return the new {@code Single} instance + * @throws NullPointerException if {@code initialItemSupplier} or {@code collector} is {@code null} * @see ReactiveX operators documentation: Reduce */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single collect(@NonNull Supplier initialValueSupplier, @NonNull BiConsumer collector) { - Objects.requireNonNull(initialValueSupplier, "initialValueSupplier is null"); + public final <@NonNull U> Single collect(@NonNull Supplier initialItemSupplier, @NonNull BiConsumer collector) { + Objects.requireNonNull(initialItemSupplier, "initialItemSupplier is null"); Objects.requireNonNull(collector, "collector is null"); - return RxJavaPlugins.onAssembly(new ObservableCollectSingle<>(this, initialValueSupplier, collector)); + return RxJavaPlugins.onAssembly(new ObservableCollectSingle<>(this, initialItemSupplier, collector)); } /** - * Collects items emitted by the finite source ObservableSource into a single mutable data structure and returns - * a Single that emits this structure. + * Collects items emitted by the finite source {@code Observable} into a single mutable data structure and returns + * a {@link Single} that emits this structure. *

- * + * *

* This is a simplified version of {@code reduce} that does not need to return the state on each pass. *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulator object to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code collectInto} does not operate by default on a particular {@link Scheduler}.
*
* * @param the accumulator and output type - * @param initialValue + * @param initialItem * the mutable data structure that will collect the items * @param collector - * a function that accepts the {@code state} and an emitted item, and modifies {@code state} + * a function that accepts the {@code state} and an emitted item, and modifies the accumulator accordingly * accordingly - * @return a Single that emits the result of collecting the values emitted by the source ObservableSource - * into a single mutable data structure + * @return the new {@code Single} instance + * @throws NullPointerException if {@code initialItem} or {@code collector} is {@code null} * @see ReactiveX operators documentation: Reduce */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single collectInto(@NonNull U initialValue, @NonNull BiConsumer collector) { - Objects.requireNonNull(initialValue, "initialValue is null"); - return collect(Functions.justSupplier(initialValue), collector); + public final <@NonNull U> Single collectInto(@NonNull U initialItem, @NonNull BiConsumer collector) { + Objects.requireNonNull(initialItem, "initialItem is null"); + return collect(Functions.justSupplier(initialItem), collector); } /** - * Transform an ObservableSource by applying a particular Transformer function to it. + * Transform the current {@code Observable} by applying a particular {@link ObservableTransformer} function to it. *

- * This method operates on the ObservableSource itself whereas {@link #lift} operates on the ObservableSource's - * Observers. + * This method operates on the {@code Observable} itself whereas {@link #lift} operates on the {@link ObservableSource}'s + * {@link Observer}s. *

- * If the operator you are creating is designed to act on the individual items emitted by a source - * ObservableSource, use {@link #lift}. If your operator is designed to transform the source ObservableSource as a whole + * If the operator you are creating is designed to act on the individual items emitted by the current + * {@code Observable}, use {@link #lift}. If your operator is designed to transform the current {@code Observable} as a whole * (for instance, by applying a particular set of existing RxJava operators to it) use {@code compose}. *

*
Scheduler:
*
{@code compose} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the value type of the output ObservableSource - * @param composer implements the function that transforms the source ObservableSource - * @return the source ObservableSource, transformed by the transformer function + * @param the value type of the output {@code ObservableSource} + * @param composer implements the function that transforms the current {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code composer} is {@code null} * @see RxJava wiki: Implementing Your Own Operators */ @SuppressWarnings("unchecked") @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable compose(@NonNull ObservableTransformer composer) { + public final <@NonNull R> Observable compose(@NonNull ObservableTransformer composer) { return wrap(((ObservableTransformer) Objects.requireNonNull(composer, "composer is null")).apply(this)); } /** - * Returns a new Observable that emits items resulting from applying a function that you supply to each item - * emitted by the source ObservableSource, where that function returns an ObservableSource, and then emitting the items - * that result from concatenating those resulting ObservableSources. + * Returns a new {@code Observable} that emits items resulting from applying a function that you supply to each item + * emitted by the current {@code Observable}, where that function returns an {@link ObservableSource}, and then emitting the items + * that result from concatenating those returned {@code ObservableSource}s. *

- * + * *

* Note that there is no guarantee where the given {@code mapper} function will be executed; it could be on the subscribing thread, * on the upstream thread signaling the new item to be mapped or on the thread where the inner source terminates. To ensure @@ -6434,28 +6806,28 @@ public final Observable compose(@NonNull ObservableTransformer{@code concatMap} does not operate by default on a particular {@link Scheduler}.

*
* - * @param the type of the inner ObservableSource sources and thus the output type + * @param the type of the inner {@code ObservableSource} sources and thus the output type * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns an - * ObservableSource - * @return an Observable that emits the result of applying the transformation function to each item emitted - * by the source ObservableSource and concatenating the ObservableSources obtained from this transformation + * a function that, when applied to an item emitted by the current {@code Observable}, returns an + * {@code ObservableSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap * @see #concatMap(Function, int, Scheduler) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable concatMap(@NonNull Function> mapper) { + public final <@NonNull R> Observable concatMap(@NonNull Function> mapper) { return concatMap(mapper, 2); } /** - * Returns a new Observable that emits items resulting from applying a function that you supply to each item - * emitted by the source ObservableSource, where that function returns an ObservableSource, and then emitting the items - * that result from concatenating those resulting ObservableSources. + * Returns a new {@code Observable} that emits items resulting from applying a function that you supply to each item + * emitted by the current {@code Observable}, where that function returns an {@link ObservableSource}, and then emitting the items + * that result from concatenating those returned {@code ObservableSource}s. *

- * + * *

* Note that there is no guarantee where the given {@code mapper} function will be executed; it could be on the subscribing thread, * on the upstream thread signaling the new item to be mapped or on the thread where the inner source terminates. To ensure @@ -6465,23 +6837,24 @@ public final Observable concatMap(@NonNull Function{@code concatMap} does not operate by default on a particular {@link Scheduler}.

*
* - * @param the type of the inner ObservableSource sources and thus the output type + * @param the type of the inner {@code ObservableSource} sources and thus the output type * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns an - * ObservableSource - * @param prefetch - * the number of elements to prefetch from the current Observable - * @return an Observable that emits the result of applying the transformation function to each item emitted - * by the source ObservableSource and concatenating the ObservableSources obtained from this transformation + * a function that, when applied to an item emitted by the current {@code Observable}, returns an + * {@code ObservableSource} + * @param bufferSize + * the number of elements expected from the current {@code Observable} to be buffered + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: FlatMap * @see #concatMap(Function, int, Scheduler) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable concatMap(@NonNull Function> mapper, int prefetch) { + public final <@NonNull R> Observable concatMap(@NonNull Function> mapper, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); if (this instanceof ScalarSupplier) { @SuppressWarnings("unchecked") T v = ((ScalarSupplier)this).get(); @@ -6490,15 +6863,15 @@ public final Observable concatMap(@NonNull Function(this, mapper, prefetch, ErrorMode.IMMEDIATE)); + return RxJavaPlugins.onAssembly(new ObservableConcatMap<>(this, mapper, bufferSize, ErrorMode.IMMEDIATE)); } /** - * Returns a new Observable that emits items resulting from applying a function that you supply to each item - * emitted by the source ObservableSource, where that function returns an ObservableSource, and then emitting the items - * that result from concatenating those resulting ObservableSources. + * Returns a new {@code Observable} that emits items resulting from applying a function that you supply to each item + * emitted by the current {@code Observable}, where that function returns an {@link ObservableSource}, and then emitting the items + * that result from concatenating those returned {@code ObservableSource}s. *

- * + * *

* The difference between {@link #concatMap(Function, int)} and this operator is that this operator guarantees the {@code mapper} * function is executed on the specified scheduler. @@ -6507,36 +6880,37 @@ public final Observable concatMap(@NonNull Function{@code concatMap} executes the given {@code mapper} function on the provided {@link Scheduler}.

*
* - * @param the type of the inner ObservableSource sources and thus the output type + * @param the type of the inner {@code ObservableSource} sources and thus the output type * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns an - * ObservableSource - * @param prefetch - * the number of elements to prefetch from the current Observable + * a function that, when applied to an item emitted by the current {@code Observable}, returns an + * {@code ObservableSource} + * @param bufferSize + * the number of elements expected from the current {@code Observable} to be buffered * @param scheduler * the scheduler where the {@code mapper} function will be executed - * @return an Observable that emits the result of applying the transformation function to each item emitted - * by the source ObservableSource and concatenating the ObservableSources obtained from this transformation + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @since 3.0.0 * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable concatMap(@NonNull Function> mapper, int prefetch, @NonNull Scheduler scheduler) { + public final <@NonNull R> Observable concatMap(@NonNull Function> mapper, int bufferSize, @NonNull Scheduler scheduler) { Objects.requireNonNull(mapper, "mapper is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new ObservableConcatMapScheduler<>(this, mapper, prefetch, ErrorMode.IMMEDIATE, scheduler)); + return RxJavaPlugins.onAssembly(new ObservableConcatMapScheduler<>(this, mapper, bufferSize, ErrorMode.IMMEDIATE, scheduler)); } /** - * Maps each of the items into an ObservableSource, subscribes to them one after the other, + * Maps each of the items into an {@link ObservableSource}, subscribes to them one after the other, * one at a time and emits their values in order - * while delaying any error from either this or any of the inner ObservableSources + * while delaying any error from either this or any of the inner {@code ObservableSource}s * till all of them terminate. *

- * + * *

* Note that there is no guarantee where the given {@code mapper} function will be executed; it could be on the subscribing thread, * on the upstream thread signaling the new item to be mapped or on the thread where the inner source terminates. To ensure @@ -6547,24 +6921,25 @@ public final Observable concatMap(@NonNull Function * * @param the result value type - * @param mapper the function that maps the items of this ObservableSource into the inner ObservableSources. - * @return the new ObservableSource instance with the concatenation behavior + * @param mapper the function that maps the items of the current {@code Observable} into the inner {@code ObservableSource}s. + * @return the new {@code Observable} instance with the concatenation behavior + * @throws NullPointerException if {@code mapper} is {@code null} * @see #concatMapDelayError(Function, boolean, int, Scheduler) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable concatMapDelayError(@NonNull Function> mapper) { + public final <@NonNull R> Observable concatMapDelayError(@NonNull Function> mapper) { return concatMapDelayError(mapper, true, bufferSize()); } /** - * Maps each of the items into an ObservableSource, subscribes to them one after the other, + * Maps each of the items into an {@link ObservableSource}, subscribes to them one after the other, * one at a time and emits their values in order - * while delaying any error from either this or any of the inner ObservableSources + * while delaying any error from either this or any of the inner {@code ObservableSource}s * till all of them terminate. *

- * + * *

* Note that there is no guarantee where the given {@code mapper} function will be executed; it could be on the subscribing thread, * on the upstream thread signaling the new item to be mapped or on the thread where the inner source terminates. To ensure @@ -6575,22 +6950,24 @@ public final Observable concatMapDelayError(@NonNull Function * * @param the result value type - * @param mapper the function that maps the items of this ObservableSource into the inner ObservableSources. + * @param mapper the function that maps the items of the current {@code Observable} into the inner {@code ObservableSource}s. * @param tillTheEnd - * if true, all errors from the outer and inner ObservableSource sources are delayed until the end, - * if false, an error from the main source is signalled when the current ObservableSource source terminates - * @param prefetch - * the number of elements to prefetch from the current Observable - * @return the new ObservableSource instance with the concatenation behavior + * if {@code true}, all errors from the outer and inner {@code ObservableSource} sources are delayed until the end, + * if {@code false}, an error from the main source is signaled when the current {@code Observable} source terminates + * @param bufferSize + * the number of elements expected from the current {@code Observable} to be buffered + * @return the new {@code Observable} instance with the concatenation behavior + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see #concatMapDelayError(Function, boolean, int, Scheduler) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable concatMapDelayError(@NonNull Function> mapper, - boolean tillTheEnd, int prefetch) { + public final <@NonNull R> Observable concatMapDelayError(@NonNull Function> mapper, + boolean tillTheEnd, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); if (this instanceof ScalarSupplier) { @SuppressWarnings("unchecked") T v = ((ScalarSupplier)this).get(); @@ -6599,109 +6976,114 @@ public final Observable concatMapDelayError(@NonNull Function(this, mapper, prefetch, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY)); + return RxJavaPlugins.onAssembly(new ObservableConcatMap<>(this, mapper, bufferSize, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY)); } /** - * Maps each of the items into an ObservableSource, subscribes to them one after the other, + * Maps each of the items into an {@link ObservableSource}, subscribes to them one after the other, * one at a time and emits their values in order - * while delaying any error from either this or any of the inner ObservableSources + * while delaying any error from either this or any of the inner {@code ObservableSource}s * till all of them terminate. *

- * + * *

*
Scheduler:
*
{@code concatMapDelayError} does not operate by default on a particular {@link Scheduler}.
*
* * @param the result value type - * @param mapper the function that maps the items of this ObservableSource into the inner ObservableSources. + * @param mapper the function that maps the items of the current {@code Observable} into the inner {@code ObservableSource}s. * @param tillTheEnd - * if true, all errors from the outer and inner ObservableSource sources are delayed until the end, - * if false, an error from the main source is signalled when the current ObservableSource source terminates - * @param prefetch - * the number of elements to prefetch from the current Observable + * if {@code true}, all errors from the outer and inner {@code ObservableSource} sources are delayed until the end, + * if {@code false}, an error from the main source is signaled when the current {@code Observable} source terminates + * @param bufferSize + * the number of elements expected from the current {@code Observable} to be buffered * @param scheduler * the scheduler where the {@code mapper} function will be executed - * @return the new ObservableSource instance with the concatenation behavior + * @return the new {@code Observable} instance with the concatenation behavior + * @throws NullPointerException if {@code mapper} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see #concatMapDelayError(Function, boolean, int) * @since 3.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable concatMapDelayError(@NonNull Function> mapper, - boolean tillTheEnd, int prefetch, @NonNull Scheduler scheduler) { + public final <@NonNull R> Observable concatMapDelayError(@NonNull Function> mapper, + boolean tillTheEnd, int bufferSize, @NonNull Scheduler scheduler) { Objects.requireNonNull(mapper, "mapper is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new ObservableConcatMapScheduler<>(this, mapper, prefetch, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY, scheduler)); + return RxJavaPlugins.onAssembly(new ObservableConcatMapScheduler<>(this, mapper, bufferSize, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY, scheduler)); } /** - * Maps a sequence of values into ObservableSources and concatenates these ObservableSources eagerly into a single - * ObservableSource. + * Maps a sequence of values into {@link ObservableSource}s and concatenates these {@code ObservableSource}s eagerly into a single + * {@code Observable} sequence. *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source ObservableSources. The operator buffers the values emitted by these ObservableSources and then drains them in + * current {@code Observable}s. The operator buffers the values emitted by these {@code ObservableSource}s and then drains them in * order, each one after the previous one completes. *

- * + * *

*
Scheduler:
*
This method does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param mapper the function that maps a sequence of values into a sequence of ObservableSources that will be + * @param mapper the function that maps a sequence of values into a sequence of {@code ObservableSource}s that will be * eagerly concatenated - * @return the new ObservableSource instance with the specified concatenation behavior + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code mapper} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable concatMapEager(@NonNull Function> mapper) { + public final <@NonNull R> Observable concatMapEager(@NonNull Function> mapper) { return concatMapEager(mapper, Integer.MAX_VALUE, bufferSize()); } /** - * Maps a sequence of values into ObservableSources and concatenates these ObservableSources eagerly into a single - * ObservableSource. + * Maps a sequence of values into {@link ObservableSource}s and concatenates these {@code ObservableSource}s eagerly into a single + * {@code Observable} sequence. *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source ObservableSources. The operator buffers the values emitted by these ObservableSources and then drains them in + * current {@code Observable}s. The operator buffers the values emitted by these {@code ObservableSource}s and then drains them in * order, each one after the previous one completes. *

- * + * *

*
Scheduler:
*
This method does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param mapper the function that maps a sequence of values into a sequence of ObservableSources that will be + * @param mapper the function that maps a sequence of values into a sequence of {@code ObservableSource}s that will be * eagerly concatenated - * @param maxConcurrency the maximum number of concurrent subscribed ObservableSources - * @param prefetch hints about the number of expected values from each inner ObservableSource, must be positive - * @return the new ObservableSource instance with the specified concatenation behavior + * @param maxConcurrency the maximum number of concurrent subscribed {@code ObservableSource}s + * @param bufferSize hints about the number of expected items from each inner {@code ObservableSource}, must be positive + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable concatMapEager(@NonNull Function> mapper, - int maxConcurrency, int prefetch) { + public final <@NonNull R> Observable concatMapEager(@NonNull Function> mapper, + int maxConcurrency, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new ObservableConcatMapEager<>(this, mapper, ErrorMode.IMMEDIATE, maxConcurrency, prefetch)); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + return RxJavaPlugins.onAssembly(new ObservableConcatMapEager<>(this, mapper, ErrorMode.IMMEDIATE, maxConcurrency, bufferSize)); } /** - * Maps a sequence of values into ObservableSources and concatenates these ObservableSources eagerly into a single - * ObservableSource. + * Maps a sequence of values into {@link ObservableSource}s and concatenates these {@code ObservableSource}s eagerly into a single + * {@code Observable} sequence. *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source ObservableSources. The operator buffers the values emitted by these ObservableSources and then drains them in + * current {@code Observable}s. The operator buffers the values emitted by these {@code ObservableSource}s and then drains them in * order, each one after the previous one completes. *

* @@ -6710,28 +7092,29 @@ public final Observable concatMapEager(@NonNull FunctionThis method does not operate by default on a particular {@link Scheduler}.

*
* @param the value type - * @param mapper the function that maps a sequence of values into a sequence of ObservableSources that will be + * @param mapper the function that maps a sequence of values into a sequence of {@code ObservableSource}s that will be * eagerly concatenated * @param tillTheEnd - * if true, all errors from the outer and inner ObservableSource sources are delayed until the end, - * if false, an error from the main source is signalled when the current ObservableSource source terminates - * @return the new ObservableSource instance with the specified concatenation behavior + * if {@code true}, all errors from the outer and inner {@code ObservableSource} sources are delayed until the end, + * if {@code false}, an error from the main source is signaled when the current {@code Observable} source terminates + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code mapper} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable concatMapEagerDelayError(@NonNull Function> mapper, + public final <@NonNull R> Observable concatMapEagerDelayError(@NonNull Function> mapper, boolean tillTheEnd) { return concatMapEagerDelayError(mapper, tillTheEnd, Integer.MAX_VALUE, bufferSize()); } /** - * Maps a sequence of values into ObservableSources and concatenates these ObservableSources eagerly into a single - * ObservableSource. + * Maps a sequence of values into {@link ObservableSource}s and concatenates these {@code ObservableSource}s eagerly into a single + * {@code Observable} sequence. *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source ObservableSources. The operator buffers the values emitted by these ObservableSources and then drains them in + * current {@code Observable}s. The operator buffers the values emitted by these {@code ObservableSource}s and then drains them in * order, each one after the previous one completes. *

* @@ -6740,42 +7123,45 @@ public final Observable concatMapEagerDelayError(@NonNull FunctionThis method does not operate by default on a particular {@link Scheduler}.

*
* @param the value type - * @param mapper the function that maps a sequence of values into a sequence of ObservableSources that will be + * @param mapper the function that maps a sequence of values into a sequence of {@code ObservableSource}s that will be * eagerly concatenated * @param tillTheEnd - * if true, exceptions from the current Observable and all the inner ObservableSources are delayed until - * all of them terminate, if false, exception from the current Observable is delayed until the - * currently running ObservableSource terminates - * @param maxConcurrency the maximum number of concurrent subscribed ObservableSources - * @param prefetch - * the number of elements to prefetch from each source ObservableSource - * @return the new ObservableSource instance with the specified concatenation behavior + * if {@code true}, exceptions from the current {@code Observable} and all the inner {@code ObservableSource}s are delayed until + * all of them terminate, if {@code false}, exception from the current {@code Observable} is delayed until the + * currently running {@code ObservableSource} terminates + * @param maxConcurrency the maximum number of concurrent subscribed {@code ObservableSource}s + * @param bufferSize + * the number of elements expected from the current {@code Observable} and each inner {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable concatMapEagerDelayError(@NonNull Function> mapper, - boolean tillTheEnd, int maxConcurrency, int prefetch) { + public final <@NonNull R> Observable concatMapEagerDelayError(@NonNull Function> mapper, + boolean tillTheEnd, int maxConcurrency, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new ObservableConcatMapEager<>(this, mapper, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY, maxConcurrency, prefetch)); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + return RxJavaPlugins.onAssembly(new ObservableConcatMapEager<>(this, mapper, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY, maxConcurrency, bufferSize)); } /** - * Maps each element of the upstream Observable into CompletableSources, subscribes to them one at a time in - * order and waits until the upstream and all CompletableSources complete. + * Maps each element of the current {@code Observable} into {@link CompletableSource}s, subscribes to them one at a time in + * order and waits until the upstream and all {@code CompletableSource}s complete. *

- * + * *

*
Scheduler:
*
{@code concatMapCompletable} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.1.6 - experimental * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns a CompletableSource - * @return a Completable that signals {@code onComplete} when the upstream and all CompletableSources complete + * a function that, when applied to an item emitted by the current {@code Observable}, returns a {@code CompletableSource} + * @return the new {@link Completable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -6786,22 +7172,24 @@ public final Completable concatMapCompletable(@NonNull Function - * + * *

*
Scheduler:
*
{@code concatMapCompletable} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.1.6 - experimental * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns a CompletableSource + * a function that, when applied to an item emitted by the current {@code Observable}, returns a {@code CompletableSource} * * @param capacityHint - * the number of upstream items expected to be buffered until the current CompletableSource, mapped from + * the number of upstream items expected to be buffered until the current {@code CompletableSource}, mapped from * the current item, completes. - * @return a Completable that signals {@code onComplete} when the upstream and all CompletableSources complete + * @return the new {@link Completable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code capacityHint} is non-positive * @since 2.2 */ @CheckReturnValue @@ -6815,10 +7203,10 @@ public final Completable concatMapCompletable(@NonNull Function - * + * *

*
Scheduler:
*
{@code concatMapCompletableDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -6827,7 +7215,8 @@ public final Completable concatMapCompletable(@NonNull Function - * + * *
*
Scheduler:
*
{@code concatMapCompletableDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -6852,13 +7241,14 @@ public final Completable concatMapCompletableDelayError(@NonNull Function - * + * *
*
Scheduler:
*
{@code concatMapCompletableDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -6883,32 +7273,32 @@ public final Completable concatMapCompletableDelayError(@NonNull Function mapper, boolean tillTheEnd, int prefetch) { + public final Completable concatMapCompletableDelayError(@NonNull Function mapper, boolean tillTheEnd, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new ObservableConcatMapCompletable<>(this, mapper, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY, prefetch)); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + return RxJavaPlugins.onAssembly(new ObservableConcatMapCompletable<>(this, mapper, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY, bufferSize)); } /** - * Returns an Observable that concatenate each item emitted by the source ObservableSource with the values in an - * Iterable corresponding to that item that is generated by a selector. + * Returns an {@code Observable} that concatenate each item emitted by the current {@code Observable} with the values in an + * {@link Iterable} corresponding to that item that is generated by a selector. *

* * @@ -6918,69 +7308,39 @@ public final Completable concatMapCompletableDelayError(@NonNull Function * * @param - * the type of item emitted by the resulting ObservableSource + * the type of item emitted by the resulting {@code Observable} * @param mapper - * a function that returns an Iterable sequence of values for when given an item emitted by the - * source ObservableSource - * @return an Observable that emits the results of concatenating the items emitted by the source ObservableSource with - * the values in the Iterables corresponding to those items, as generated by {@code collectionSelector} + * a function that returns an {@code Iterable} sequence of values for when given an item emitted by the + * current {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable concatMapIterable(@NonNull Function> mapper) { + public final <@NonNull U> Observable concatMapIterable(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new ObservableFlattenIterable<>(this, mapper)); } /** - * Returns an Observable that concatenate each item emitted by the source ObservableSource with the values in an - * Iterable corresponding to that item that is generated by a selector. + * Maps the upstream items into {@link MaybeSource}s and subscribes to them one after the + * other succeeds or completes, emits their success value if available or terminates immediately if + * either the current {@code Observable} or the current inner {@code MaybeSource} fail. *

- * - * + * *

*
Scheduler:
- *
{@code concatMapIterable} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param - * the type of item emitted by the resulting ObservableSource - * @param mapper - * a function that returns an Iterable sequence of values for when given an item emitted by the - * source ObservableSource - * @param prefetch - * the number of elements to prefetch from the current Observable - * @return an Observable that emits the results of concatenating the items emitted by the source ObservableSource with - * the values in the Iterables corresponding to those items, as generated by {@code collectionSelector} - * @see ReactiveX operators documentation: FlatMap - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public final Observable concatMapIterable(@NonNull Function> mapper, int prefetch) { - Objects.requireNonNull(mapper, "mapper is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return concatMap(ObservableInternalHelper.flatMapIntoIterable(mapper), prefetch); - } - - /** - * Maps the upstream items into {@link MaybeSource}s and subscribes to them one after the - * other succeeds or completes, emits their success value if available or terminates immediately if - * either this {@code Observable} or the current inner {@code MaybeSource} fail. - *

- * - *

- *
Scheduler:
- *
{@code concatMapMaybe} does not operate by default on a particular {@link Scheduler}.
+ *
{@code concatMapMaybe} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.1.11 - experimental * @param the result type of the inner {@code MaybeSource}s * @param mapper the function called with the upstream item and should return * a {@code MaybeSource} to become the next source to * be subscribed to - * @return a new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see #concatMapMaybeDelayError(Function) * @see #concatMapMaybe(Function, int) * @since 2.2 @@ -6988,16 +7348,16 @@ public final Observable concatMapIterable(@NonNull Function Observable concatMapMaybe(@NonNull Function> mapper) { + public final <@NonNull R> Observable concatMapMaybe(@NonNull Function> mapper) { return concatMapMaybe(mapper, 2); } /** * Maps the upstream items into {@link MaybeSource}s and subscribes to them one after the * other succeeds or completes, emits their success value if available or terminates immediately if - * either this {@code Observable} or the current inner {@code MaybeSource} fail. + * either the current {@code Observable} or the current inner {@code MaybeSource} fail. *

- * + * *

*
Scheduler:
*
{@code concatMapMaybe} does not operate by default on a particular {@link Scheduler}.
@@ -7007,11 +7367,11 @@ public final Observable concatMapMaybe(@NonNull Function Observable concatMapMaybe(@NonNull Function Observable concatMapMaybe(@NonNull Function> mapper, int prefetch) { + public final <@NonNull R> Observable concatMapMaybe(@NonNull Function> mapper, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new ObservableConcatMapMaybe<>(this, mapper, ErrorMode.IMMEDIATE, prefetch)); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + return RxJavaPlugins.onAssembly(new ObservableConcatMapMaybe<>(this, mapper, ErrorMode.IMMEDIATE, bufferSize)); } /** * Maps the upstream items into {@link MaybeSource}s and subscribes to them one after the * other terminates, emits their success value if available and delaying all errors - * till both this {@code Observable} and all inner {@code MaybeSource}s terminate. + * till both the current {@code Observable} and all inner {@code MaybeSource}s terminate. *

- * + * *

*
Scheduler:
*
{@code concatMapMaybeDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -7040,7 +7400,8 @@ public final Observable concatMapMaybe(@NonNull Function Observable concatMapMaybe(@NonNull Function Observable concatMapMaybeDelayError(@NonNull Function> mapper) { + public final <@NonNull R> Observable concatMapMaybeDelayError(@NonNull Function> mapper) { return concatMapMaybeDelayError(mapper, true, 2); } /** * Maps the upstream items into {@link MaybeSource}s and subscribes to them one after the * other terminates, emits their success value if available and optionally delaying all errors - * till both this {@code Observable} and all inner {@code MaybeSource}s terminate. + * till both the current {@code Observable} and all inner {@code MaybeSource}s terminate. *

- * + * *

*
Scheduler:
*
{@code concatMapMaybeDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -7067,13 +7428,14 @@ public final Observable concatMapMaybeDelayError(@NonNull Function Observable concatMapMaybeDelayError(@NonNull Function Observable concatMapMaybeDelayError(@NonNull Function> mapper, boolean tillTheEnd) { + public final <@NonNull R> Observable concatMapMaybeDelayError(@NonNull Function> mapper, boolean tillTheEnd) { return concatMapMaybeDelayError(mapper, tillTheEnd, 2); } /** * Maps the upstream items into {@link MaybeSource}s and subscribes to them one after the * other terminates, emits their success value if available and optionally delaying all errors - * till both this {@code Observable} and all inner {@code MaybeSource}s terminate. + * till both the current {@code Observable} and all inner {@code MaybeSource}s terminate. *

- * + * *

*
Scheduler:
*
{@code concatMapMaybeDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -7100,35 +7462,35 @@ public final Observable concatMapMaybeDelayError(@NonNull Function Observable concatMapMaybeDelayError(@NonNull Function> mapper, boolean tillTheEnd, int prefetch) { + public final <@NonNull R> Observable concatMapMaybeDelayError(@NonNull Function> mapper, boolean tillTheEnd, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new ObservableConcatMapMaybe<>(this, mapper, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY, prefetch)); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + return RxJavaPlugins.onAssembly(new ObservableConcatMapMaybe<>(this, mapper, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY, bufferSize)); } /** * Maps the upstream items into {@link SingleSource}s and subscribes to them one after the * other succeeds, emits their success values or terminates immediately if - * either this {@code Observable} or the current inner {@code SingleSource} fail. + * either the current {@code Observable} or the current inner {@code SingleSource} fail. *

- * + * *

*
Scheduler:
*
{@code concatMapSingle} does not operate by default on a particular {@link Scheduler}.
@@ -7138,7 +7500,8 @@ public final Observable concatMapMaybeDelayError(@NonNull Function Observable concatMapMaybeDelayError(@NonNull Function Observable concatMapSingle(@NonNull Function> mapper) { + public final <@NonNull R> Observable concatMapSingle(@NonNull Function> mapper) { return concatMapSingle(mapper, 2); } /** * Maps the upstream items into {@link SingleSource}s and subscribes to them one after the * other succeeds, emits their success values or terminates immediately if - * either this {@code Observable} or the current inner {@code SingleSource} fail. + * either the current {@code Observable} or the current inner {@code SingleSource} fail. *

- * + * *

*
Scheduler:
*
{@code concatMapSingle} does not operate by default on a particular {@link Scheduler}.
@@ -7165,11 +7528,11 @@ public final Observable concatMapSingle(@NonNull Function Observable concatMapSingle(@NonNull Function Observable concatMapSingle(@NonNull Function> mapper, int prefetch) { + public final <@NonNull R> Observable concatMapSingle(@NonNull Function> mapper, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new ObservableConcatMapSingle<>(this, mapper, ErrorMode.IMMEDIATE, prefetch)); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + return RxJavaPlugins.onAssembly(new ObservableConcatMapSingle<>(this, mapper, ErrorMode.IMMEDIATE, bufferSize)); } /** * Maps the upstream items into {@link SingleSource}s and subscribes to them one after the * other succeeds or fails, emits their success values and delays all errors - * till both this {@code Observable} and all inner {@code SingleSource}s terminate. + * till both the current {@code Observable} and all inner {@code SingleSource}s terminate. *

- * + * *

*
Scheduler:
*
{@code concatMapSingleDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -7198,7 +7561,8 @@ public final Observable concatMapSingle(@NonNull Function Observable concatMapSingle(@NonNull Function Observable concatMapSingleDelayError(@NonNull Function> mapper) { + public final <@NonNull R> Observable concatMapSingleDelayError(@NonNull Function> mapper) { return concatMapSingleDelayError(mapper, true, 2); } /** * Maps the upstream items into {@link SingleSource}s and subscribes to them one after the * other succeeds or fails, emits their success values and optionally delays all errors - * till both this {@code Observable} and all inner {@code SingleSource}s terminate. + * till both the current {@code Observable} and all inner {@code SingleSource}s terminate. *

- * + * *

*
Scheduler:
*
{@code concatMapSingleDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -7225,13 +7589,14 @@ public final Observable concatMapSingleDelayError(@NonNull Function Observable concatMapSingleDelayError(@NonNull Function Observable concatMapSingleDelayError(@NonNull Function> mapper, boolean tillTheEnd) { + public final <@NonNull R> Observable concatMapSingleDelayError(@NonNull Function> mapper, boolean tillTheEnd) { return concatMapSingleDelayError(mapper, tillTheEnd, 2); } /** * Maps the upstream items into {@link SingleSource}s and subscribes to them one after the * other succeeds or fails, emits their success values and optionally delays errors - * till both this {@code Observable} and all inner {@code SingleSource}s terminate. + * till both the current {@code Observable} and all inner {@code SingleSource}s terminate. *

- * + * *

*
Scheduler:
*
{@code concatMapSingleDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -7258,43 +7623,43 @@ public final Observable concatMapSingleDelayError(@NonNull Function Observable concatMapSingleDelayError(@NonNull Function> mapper, boolean tillTheEnd, int prefetch) { + public final <@NonNull R> Observable concatMapSingleDelayError(@NonNull Function> mapper, boolean tillTheEnd, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new ObservableConcatMapSingle<>(this, mapper, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY, prefetch)); + ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + return RxJavaPlugins.onAssembly(new ObservableConcatMapSingle<>(this, mapper, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY, bufferSize)); } /** - * Returns an Observable that emits the items emitted from the current ObservableSource, then the next, one after - * the other, without interleaving them. + * Returns an {@code Observable} that first emits the items emitted from the current {@code Observable}, then items + * from the {@code other} {@link ObservableSource} without interleaving them. *

- * + * *

*
Scheduler:
*
{@code concatWith} does not operate by default on a particular {@link Scheduler}.
*
* * @param other - * an ObservableSource to be concatenated after the current - * @return an Observable that emits items emitted by the two source ObservableSources, one after the other, - * without interleaving them + * an {@code ObservableSource} to be concatenated after the current + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: Concat */ @CheckReturnValue @@ -7306,17 +7671,18 @@ public final Observable concatWith(@NonNull ObservableSource oth } /** - * Returns an {@code Observable} that emits the items from this {@code Observable} followed by the success item or error event - * of the other {@link SingleSource}. + * Returns an {@code Observable} that emits the items from the current {@code Observable} followed by the success item or error event + * of the {@code other} {@link SingleSource}. *

- * + * *

*
Scheduler:
*
{@code concatWith} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.1.10 - experimental - * @param other the SingleSource whose signal should be emitted after this {@code Observable} completes normally. - * @return the new Observable instance + * @param other the {@code SingleSource} whose signal should be emitted after the current {@code Observable} completes normally. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -7328,17 +7694,18 @@ public final Observable concatWith(@NonNull SingleSource other) } /** - * Returns an {@code Observable} that emits the items from this {@code Observable} followed by the success item or terminal events + * Returns an {@code Observable} that emits the items from the current {@code Observable} followed by the success item or terminal events * of the other {@link MaybeSource}. *

- * + * *

*
Scheduler:
*
{@code concatWith} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.1.10 - experimental - * @param other the MaybeSource whose signal should be emitted after this Observable completes normally. - * @return the new Observable instance + * @param other the {@code MaybeSource} whose signal should be emitted after the current {@code Observable} completes normally. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -7350,17 +7717,18 @@ public final Observable concatWith(@NonNull MaybeSource other) { } /** - * Returns an {@code Observable} that emits items from this {@code Observable} and when it completes normally, the + * Returns an {@code Observable} that emits items from the current {@code Observable} and when it completes normally, the * other {@link CompletableSource} is subscribed to and the returned {@code Observable} emits its terminal events. *

- * + * *

*
Scheduler:
*
{@code concatWith} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.1.10 - experimental * @param other the {@code CompletableSource} to subscribe to once the current {@code Observable} completes normally - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -7372,41 +7740,40 @@ public final Observable concatWith(@NonNull CompletableSource other) { } /** - * Returns a Single that emits a Boolean that indicates whether the source ObservableSource emitted a + * Returns a {@link Single} that emits a {@link Boolean} that indicates whether the current {@code Observable} emitted a * specified item. *

- * + * *

*
Scheduler:
*
{@code contains} does not operate by default on a particular {@link Scheduler}.
*
* - * @param element - * the item to search for in the emissions from the source ObservableSource - * @return a Single that emits {@code true} if the specified item is emitted by the source ObservableSource, - * or {@code false} if the source ObservableSource completes without emitting that item + * @param item + * the item to search for in the emissions from the current {@code Observable} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code item} is {@code null} * @see ReactiveX operators documentation: Contains */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single contains(@NonNull Object element) { - Objects.requireNonNull(element, "element is null"); - return any(Functions.equalsWith(element)); + public final Single contains(@NonNull Object item) { + Objects.requireNonNull(item, "item is null"); + return any(Functions.equalsWith(item)); } /** - * Returns a Single that counts the total number of items emitted by the source ObservableSource and emits - * this count as a 64-bit Long. + * Returns a {@link Single} that counts the total number of items emitted by the current {@code Observable} and emits + * this count as a 64-bit {@link Long}. *

- * + * *

*
Scheduler:
*
{@code count} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a Single that emits a single item: the number of items emitted by the source ObservableSource as a - * 64-bit Long item + * @return the new {@code Single} instance * @see ReactiveX operators documentation: Count */ @CheckReturnValue @@ -7417,10 +7784,11 @@ public final Single count() { } /** - * Returns an Observable that mirrors the source ObservableSource, except that it drops items emitted by the - * source ObservableSource that are followed by another item within a computed debounce duration. + * Returns an {@code Observable} that mirrors the current {@code Observable}, except that it drops items emitted by the + * current {@code Observable} that are followed by another item within a computed debounce duration + * denoted by an item emission or completion from a generated inner {@link ObservableSource} for that original item. *

- * + * *

* The delivery of the item happens on the thread of the first {@code onNext} or {@code onComplete} * signal of the generated {@code ObservableSource} sequence, @@ -7436,31 +7804,31 @@ public final Single count() { * * @param * the debounce value type (ignored) - * @param debounceSelector - * function to retrieve a sequence that indicates the throttle duration for each item - * @return an Observable that omits items emitted by the source ObservableSource that are followed by another item - * within a computed debounce duration + * @param debounceIndicator + * function to return a sequence that indicates the throttle duration for each item via its own emission or completion + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code debounceIndicator} is {@code null} * @see ReactiveX operators documentation: Debounce */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable debounce(@NonNull Function> debounceSelector) { - Objects.requireNonNull(debounceSelector, "debounceSelector is null"); - return RxJavaPlugins.onAssembly(new ObservableDebounce<>(this, debounceSelector)); + public final <@NonNull U> Observable debounce(@NonNull Function> debounceIndicator) { + Objects.requireNonNull(debounceIndicator, "debounceIndicator is null"); + return RxJavaPlugins.onAssembly(new ObservableDebounce<>(this, debounceIndicator)); } /** - * Returns an Observable that mirrors the source ObservableSource, except that it drops items emitted by the - * source ObservableSource that are followed by newer items before a timeout value expires. The timer resets on + * Returns an {@code Observable} that mirrors the current {@code Observable}, except that it drops items emitted by the + * current {@code Observable} that are followed by newer items before a timeout value expires. The timer resets on * each emission. *

- * Note: If items keep being emitted by the source ObservableSource faster than the timeout then no items - * will be emitted by the resulting ObservableSource. + * Note: If items keep being emitted by the current {@code Observable} faster than the timeout then no items + * will be emitted by the resulting {@code Observable}. *

- * + * *

- * Delivery of the item after the grace period happens on the {@code computation} {@code Scheduler}'s + * Delivery of the item after the grace period happens on the {@code computation} {@link Scheduler}'s * {@code Worker} which if takes too long, a newer item may arrive from the upstream, causing the * {@code Worker}'s task to get disposed, which may also interrupt any downstream blocking operation * (yielding an {@code InterruptedException}). It is recommended processing items @@ -7468,17 +7836,17 @@ public final Observable debounce(@NonNull Function *

Scheduler:
- *
{@code debounce} operates by default on the {@code computation} {@link Scheduler}.
+ *
{@code debounce} operates by default on the {@code computation} {@code Scheduler}.
*
* * @param timeout - * the length of the window of time that must pass after the emission of an item from the source - * ObservableSource in which that ObservableSource emits no items in order for the item to be emitted by the - * resulting ObservableSource + * the length of the window of time that must pass after the emission of an item from the current + * {@code Observable} in which the {@code Observable} emits no items in order for the item to be emitted by the + * resulting {@code Observable} * @param unit * the unit of time for the specified {@code timeout} - * @return an Observable that filters out items from the source ObservableSource that are too quickly followed by - * newer items + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Debounce * @see #throttleWithTimeout(long, TimeUnit) */ @@ -7490,14 +7858,14 @@ public final Observable debounce(long timeout, @NonNull TimeUnit unit) { } /** - * Returns an Observable that mirrors the source ObservableSource, except that it drops items emitted by the - * source ObservableSource that are followed by newer items before a timeout value expires on a specified - * Scheduler. The timer resets on each emission. + * Returns an {@code Observable} that mirrors the current {@code Observable}, except that it drops items emitted by the + * current {@code Observable} that are followed by newer items before a timeout value expires on a specified + * {@link Scheduler}. The timer resets on each emission. *

- * Note: If items keep being emitted by the source ObservableSource faster than the timeout then no items - * will be emitted by the resulting ObservableSource. + * Note: If items keep being emitted by the current {@code Observable} faster than the timeout then no items + * will be emitted by the resulting {@code Observable}. *

- * + * *

* Delivery of the item after the grace period happens on the given {@code Scheduler}'s * {@code Worker} which if takes too long, a newer item may arrive from the upstream, causing the @@ -7507,19 +7875,19 @@ public final Observable debounce(long timeout, @NonNull TimeUnit unit) { * {@code debounce} itself. *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param timeout - * the time each item has to be "the most recent" of those emitted by the source ObservableSource to + * the time each item has to be "the most recent" of those emitted by the current {@code Observable} to * ensure that it's not dropped * @param unit * the unit of time for the specified {@code timeout} * @param scheduler - * the {@link Scheduler} to use internally to manage the timers that handle the timeout for each + * the {@code Scheduler} to use internally to manage the timers that handle the timeout for each * item - * @return an Observable that filters out items from the source ObservableSource that are too quickly followed by - * newer items + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Debounce * @see #throttleWithTimeout(long, TimeUnit, Scheduler) */ @@ -7529,23 +7897,71 @@ public final Observable debounce(long timeout, @NonNull TimeUnit unit) { public final Observable debounce(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new ObservableDebounceTimed<>(this, timeout, unit, scheduler)); + return RxJavaPlugins.onAssembly(new ObservableDebounceTimed<>(this, timeout, unit, scheduler, null)); + } + + /** + * Returns an {@code Observable} that mirrors the current {@code Observable}, except that it drops items emitted by the + * current {@code Observable} that are followed by newer items before a timeout value expires on a specified + * {@link Scheduler}. The timer resets on each emission. + *

+ * Note: If items keep being emitted by the current {@code Observable} faster than the timeout then no items + * will be emitted by the resulting {@code Observable}. + *

+ * + *

+ * Delivery of the item after the grace period happens on the given {@code Scheduler}'s + * {@code Worker} which if takes too long, a newer item may arrive from the upstream, causing the + * {@code Worker}'s task to get disposed, which may also interrupt any downstream blocking operation + * (yielding an {@code InterruptedException}). It is recommended processing items + * that may take long time to be moved to another thread via {@link #observeOn} applied after + * {@code debounce} itself. + *

+ *
Scheduler:
+ *
You specify which {@code Scheduler} this operator will use.
+ *
+ * + * @param timeout + * the time each item has to be "the most recent" of those emitted by the current {@code Observable} to + * ensure that it's not dropped + * @param unit + * the unit of time for the specified {@code timeout} + * @param scheduler + * the {@code Scheduler} to use internally to manage the timers that handle the timeout for each + * item + * @param onDropped + * called with the current entry when it has been replaced by a new one + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} } or {@code onDropped} is {@code null} + * @see ReactiveX operators documentation: Debounce + * @see #throttleWithTimeout(long, TimeUnit, Scheduler, Consumer) + * @since 3.1.6 - Experimental + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.CUSTOM) + @NonNull + @Experimental + public final Observable debounce(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + Objects.requireNonNull(onDropped, "onDropped is null"); + return RxJavaPlugins.onAssembly(new ObservableDebounceTimed<>(this, timeout, unit, scheduler, onDropped)); } /** - * Returns an Observable that emits the items emitted by the source ObservableSource or a specified default item - * if the source ObservableSource is empty. + * Returns an {@code Observable} that emits the items emitted by the current {@code Observable} or a specified default item + * if the current {@code Observable} is empty. *

- * + * *

*
Scheduler:
*
{@code defaultIfEmpty} does not operate by default on a particular {@link Scheduler}.
*
* * @param defaultItem - * the item to emit if the source ObservableSource emits no items - * @return an Observable that emits either the specified default item if the source ObservableSource emits no - * items, or the items emitted by the source ObservableSource + * the item to emit if the current {@code Observable} emits no items + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX operators documentation: DefaultIfEmpty */ @CheckReturnValue @@ -7557,13 +7973,13 @@ public final Observable defaultIfEmpty(@NonNull T defaultItem) { } /** - * Returns an Observable that delays the emissions of the source ObservableSource via another ObservableSource on a - * per-item basis. + * Returns an {@code Observable} that delays the emissions of the current {@code Observable} via + * a per-item derived {@link ObservableSource}'s item emission or termination, on a per source item basis. *

- * + * *

- * Note: the resulting ObservableSource will immediately propagate any {@code onError} notification - * from the source ObservableSource. + * Note: the resulting {@code Observable} will immediately propagate any {@code onError} notification + * from the current {@code Observable}. *

*
Scheduler:
*
This version of {@code delay} does not operate by default on a particular {@link Scheduler}.
@@ -7571,139 +7987,146 @@ public final Observable defaultIfEmpty(@NonNull T defaultItem) { * * @param * the item delay value type (ignored) - * @param itemDelay - * a function that returns an ObservableSource for each item emitted by the source ObservableSource, which is - * then used to delay the emission of that item by the resulting ObservableSource until the ObservableSource + * @param itemDelayIndicator + * a function that returns an {@code ObservableSource} for each item emitted by the current {@code Observable}, which is + * then used to delay the emission of that item by the resulting {@code Observable} until the {@code ObservableSource} * returned from {@code itemDelay} emits an item - * @return an Observable that delays the emissions of the source ObservableSource via another ObservableSource on a - * per-item basis + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code itemDelayIndicator} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable delay(@NonNull Function> itemDelay) { - Objects.requireNonNull(itemDelay, "itemDelay is null"); - return flatMap(ObservableInternalHelper.itemDelay(itemDelay)); + public final <@NonNull U> Observable delay(@NonNull Function> itemDelayIndicator) { + Objects.requireNonNull(itemDelayIndicator, "itemDelayIndicator is null"); + return flatMap(ObservableInternalHelper.itemDelay(itemDelayIndicator)); } /** - * Returns an Observable that emits the items emitted by the source ObservableSource shifted forward in time by a - * specified delay. Error notifications from the source ObservableSource are not delayed. + * Returns an {@code Observable} that emits the items emitted by the current {@code Observable} shifted forward in time by a + * specified delay. An error notification from the current {@code Observable} is not delayed. *

- * + * *

*
Scheduler:
*
This version of {@code delay} operates by default on the {@code computation} {@link Scheduler}.
*
* - * @param delay + * @param time * the delay to shift the source by * @param unit * the {@link TimeUnit} in which {@code period} is defined - * @return the source ObservableSource shifted in time by the specified delay + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Delay + * @see #delay(long, TimeUnit, boolean) + * @see #delay(long, TimeUnit, Scheduler) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Observable delay(long delay, @NonNull TimeUnit unit) { - return delay(delay, unit, Schedulers.computation(), false); + public final Observable delay(long time, @NonNull TimeUnit unit) { + return delay(time, unit, Schedulers.computation(), false); } /** - * Returns an Observable that emits the items emitted by the source ObservableSource shifted forward in time by a - * specified delay. If {@code delayError} is true, error notifications will also be delayed. + * Returns an {@code Observable} that emits the items emitted by the current {@code Observable} shifted forward in time by a + * specified delay. If {@code delayError} is {@code true}, error notifications will also be delayed. *

- * + * *

*
Scheduler:
*
This version of {@code delay} operates by default on the {@code computation} {@link Scheduler}.
*
* - * @param delay + * @param time * the delay to shift the source by * @param unit * the {@link TimeUnit} in which {@code period} is defined * @param delayError - * if true, the upstream exception is signalled with the given delay, after all preceding normal elements, - * if false, the upstream exception is signalled immediately - * @return the source ObservableSource shifted in time by the specified delay + * if {@code true}, the upstream exception is signaled with the given delay, after all preceding normal elements, + * if {@code false}, the upstream exception is signaled immediately + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Delay + * @see #delay(long, TimeUnit, Scheduler, boolean) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Observable delay(long delay, @NonNull TimeUnit unit, boolean delayError) { - return delay(delay, unit, Schedulers.computation(), delayError); + public final Observable delay(long time, @NonNull TimeUnit unit, boolean delayError) { + return delay(time, unit, Schedulers.computation(), delayError); } /** - * Returns an Observable that emits the items emitted by the source ObservableSource shifted forward in time by a - * specified delay. Error notifications from the source ObservableSource are not delayed. + * Returns an {@code Observable} that emits the items emitted by the current {@code Observable} shifted forward in time by a + * specified delay. An error notification from the current {@code Observable} is not delayed. *

- * + * *

*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
* - * @param delay + * @param time * the delay to shift the source by * @param unit * the time unit of {@code delay} * @param scheduler - * the {@link Scheduler} to use for delaying - * @return the source ObservableSource shifted in time by the specified delay + * the {@code Scheduler} to use for delaying + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable delay(long delay, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return delay(delay, unit, scheduler, false); + public final Observable delay(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + return delay(time, unit, scheduler, false); } /** - * Returns an Observable that emits the items emitted by the source ObservableSource shifted forward in time by a - * specified delay. If {@code delayError} is true, error notifications will also be delayed. + * Returns an {@code Observable} that emits the items emitted by the current {@code Observable} shifted forward in time by a + * specified delay. If {@code delayError} is {@code true}, error notifications will also be delayed. *

- * + * *

*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
* - * @param delay + * @param time * the delay to shift the source by * @param unit * the time unit of {@code delay} * @param scheduler - * the {@link Scheduler} to use for delaying + * the {@code Scheduler} to use for delaying * @param delayError - * if true, the upstream exception is signalled with the given delay, after all preceding normal elements, - * if false, the upstream exception is signalled immediately - * @return the source ObservableSource shifted in time by the specified delay + * if {@code true}, the upstream exception is signaled with the given delay, after all preceding normal elements, + * if {@code false}, the upstream exception is signaled immediately + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable delay(long delay, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError) { + public final Observable delay(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new ObservableDelay<>(this, delay, unit, scheduler, delayError)); + return RxJavaPlugins.onAssembly(new ObservableDelay<>(this, time, unit, scheduler, delayError)); } /** - * Returns an Observable that delays the subscription to and emissions from the source ObservableSource via another - * ObservableSource on a per-item basis. + * Returns an {@code Observable} that delays the subscription to and emissions from the current {@code Observable} via + * {@link ObservableSource}s for the subscription itself and on a per-item basis. *

- * + * *

- * Note: the resulting ObservableSource will immediately propagate any {@code onError} notification - * from the source ObservableSource. + * Note: the resulting {@code Observable} will immediately propagate any {@code onError} notification + * from the current {@code Observable}. *

*
Scheduler:
*
This version of {@code delay} does not operate by default on a particular {@link Scheduler}.
@@ -7713,106 +8136,107 @@ public final Observable delay(long delay, @NonNull TimeUnit unit, @NonNull Sc * the subscription delay value type (ignored) * @param * the item delay value type (ignored) - * @param subscriptionDelay - * a function that returns an ObservableSource that triggers the subscription to the source ObservableSource + * @param subscriptionIndicator + * a function that returns an {@code ObservableSource} that triggers the subscription to the current {@code Observable} * once it emits any item - * @param itemDelay - * a function that returns an ObservableSource for each item emitted by the source ObservableSource, which is - * then used to delay the emission of that item by the resulting ObservableSource until the ObservableSource + * @param itemDelayIndicator + * a function that returns an {@code ObservableSource} for each item emitted by the current {@code Observable}, which is + * then used to delay the emission of that item by the resulting {@code Observable} until the {@code ObservableSource} * returned from {@code itemDelay} emits an item - * @return an Observable that delays the subscription and emissions of the source ObservableSource via another - * ObservableSource on a per-item basis + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code subscriptionIndicator} or {@code itemDelayIndicator} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable delay(@NonNull ObservableSource subscriptionDelay, - @NonNull Function> itemDelay) { - return delaySubscription(subscriptionDelay).delay(itemDelay); + public final <@NonNull U, @NonNull V> Observable delay(@NonNull ObservableSource subscriptionIndicator, + @NonNull Function> itemDelayIndicator) { + return delaySubscription(subscriptionIndicator).delay(itemDelayIndicator); } /** - * Returns an Observable that delays the subscription to this Observable - * until the other Observable emits an element or completes normally. + * Returns an {@code Observable} that delays the subscription to the current {@code Observable} + * until the other {@link ObservableSource} emits an element or completes normally. *

- * + * *

*
Scheduler:
*
This method does not operate by default on a particular {@link Scheduler}.
*
* - * @param the value type of the other Observable, irrelevant - * @param other the other Observable that should trigger the subscription - * to this Observable. - * @return an Observable that delays the subscription to this Observable - * until the other Observable emits an element or completes normally. + * @param the value type of the other {@code Observable}, irrelevant + * @param subscriptionIndicator the other {@code ObservableSource} that should trigger the subscription + * to the current {@code Observable}. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code subscriptionIndicator} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable delaySubscription(@NonNull ObservableSource other) { - Objects.requireNonNull(other, "other is null"); - return RxJavaPlugins.onAssembly(new ObservableDelaySubscriptionOther<>(this, other)); + public final <@NonNull U> Observable delaySubscription(@NonNull ObservableSource subscriptionIndicator) { + Objects.requireNonNull(subscriptionIndicator, "subscriptionIndicator is null"); + return RxJavaPlugins.onAssembly(new ObservableDelaySubscriptionOther<>(this, subscriptionIndicator)); } /** - * Returns an Observable that delays the subscription to the source ObservableSource by a given amount of time. + * Returns an {@code Observable} that delays the subscription to the current {@code Observable} by a given amount of time. *

- * + * *

*
Scheduler:
*
This version of {@code delaySubscription} operates by default on the {@code computation} {@link Scheduler}.
*
* - * @param delay + * @param time * the time to delay the subscription * @param unit * the time unit of {@code delay} - * @return an Observable that delays the subscription to the source ObservableSource by the given amount + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Observable delaySubscription(long delay, @NonNull TimeUnit unit) { - return delaySubscription(delay, unit, Schedulers.computation()); + public final Observable delaySubscription(long time, @NonNull TimeUnit unit) { + return delaySubscription(time, unit, Schedulers.computation()); } /** - * Returns an Observable that delays the subscription to the source ObservableSource by a given amount of time, - * both waiting and subscribing on a given Scheduler. + * Returns an {@code Observable} that delays the subscription to the current {@code Observable} by a given amount of time, + * both waiting and subscribing on a given {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* - * @param delay + * @param time * the time to delay the subscription * @param unit * the time unit of {@code delay} * @param scheduler - * the Scheduler on which the waiting and subscription will happen - * @return an Observable that delays the subscription to the source ObservableSource by a given - * amount, waiting and subscribing on the given Scheduler + * the {@code Scheduler} on which the waiting and subscription will happen + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Delay */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable delaySubscription(long delay, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return delaySubscription(timer(delay, unit, scheduler)); + public final Observable delaySubscription(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + return delaySubscription(timer(time, unit, scheduler)); } /** - * Returns an Observable that reverses the effect of {@link #materialize materialize} by transforming the + * Returns an {@code Observable} that reverses the effect of {@link #materialize materialize} by transforming the * {@link Notification} objects extracted from the source items via a selector function - * into their respective {@code Observer} signal types. + * into their respective {@link Observer} signal types. *

- * + * *

* The intended use of the {@code selector} function is to perform a * type-safe identity mapping (see example) on a source that is already of type @@ -7822,7 +8246,7 @@ public final Observable delaySubscription(long delay, @NonNull TimeUnit unit, *

* When the upstream signals an {@link Notification#createOnError(Throwable) onError} or * {@link Notification#createOnComplete() onComplete} item, the - * returned Observable disposes of the flow and terminates with that type of terminal event: + * returned {@code Observable} disposes of the flow and terminates with that type of terminal event: *


      * Observable.just(createOnNext(1), createOnComplete(), createOnNext(2))
      * .doOnDispose(() -> System.out.println("Disposed!"));
@@ -7847,38 +8271,38 @@ public final Observable delaySubscription(long delay, @NonNull TimeUnit unit,
      * 

History: 2.2.4 - experimental * * @param the output value type - * @param selector function that returns the upstream item and should return a Notification to signal + * @param selector function that returns the upstream item and should return a {@code Notification} to signal * the corresponding {@code Observer} event to the downstream. - * @return an Observable that emits the items and notifications embedded in the {@link Notification} objects - * selected from the items emitted by the source ObservableSource + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code selector} is {@code null} * @see ReactiveX operators documentation: Dematerialize * @since 3.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable dematerialize(@NonNull Function> selector) { + public final <@NonNull R> Observable dematerialize(@NonNull Function> selector) { Objects.requireNonNull(selector, "selector is null"); return RxJavaPlugins.onAssembly(new ObservableDematerialize<>(this, selector)); } /** - * Returns an Observable that emits all items emitted by the source ObservableSource that are distinct + * Returns an {@code Observable} that emits all items emitted by the current {@code Observable} that are distinct * based on {@link Object#equals(Object)} comparison. *

- * + * *

* It is recommended the elements' class {@code T} in the flow overrides the default {@code Object.equals()} * and {@link Object#hashCode()} to provide meaningful comparison between items as the default Java * implementation only considers reference equivalence. *

- * By default, {@code distinct()} uses an internal {@link java.util.HashSet} per Observer to remember + * By default, {@code distinct()} uses an internal {@link HashSet} per {@link Observer} to remember * previously seen items and uses {@link java.util.Set#add(Object)} returning {@code false} as the * indicator for duplicates. *

* Note that this internal {@code HashSet} may grow unbounded as items won't be removed from it by * the operator. Therefore, using very long or infinite upstream (with very distinct elements) may lead - * to {@code OutOfMemoryError}. + * to {@link OutOfMemoryError}. *

* Customizing the retention policy can happen only by providing a custom {@link java.util.Collection} implementation * to the {@link #distinct(Function, Supplier)} overload. @@ -7887,8 +8311,7 @@ public final Observable dematerialize(@NonNull Function{@code distinct} does not operate by default on a particular {@link Scheduler}.

*
* - * @return an Observable that emits only those items emitted by the source ObservableSource that are distinct from - * each other + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Distinct * @see #distinct(Function) * @see #distinct(Function, Supplier) @@ -7901,23 +8324,23 @@ public final Observable distinct() { } /** - * Returns an Observable that emits all items emitted by the source ObservableSource that are distinct according + * Returns an {@code Observable} that emits all items emitted by the current {@code Observable} that are distinct according * to a key selector function and based on {@link Object#equals(Object)} comparison of the objects * returned by the key selector function. *

- * + * *

* It is recommended the keys' class {@code K} overrides the default {@code Object.equals()} * and {@link Object#hashCode()} to provide meaningful comparison between the key objects as the default * Java implementation only considers reference equivalence. *

- * By default, {@code distinct()} uses an internal {@link java.util.HashSet} per Observer to remember + * By default, {@code distinct()} uses an internal {@link HashSet} per {@link Observer} to remember * previously seen keys and uses {@link java.util.Set#add(Object)} returning {@code false} as the * indicator for duplicates. *

* Note that this internal {@code HashSet} may grow unbounded as keys won't be removed from it by * the operator. Therefore, using very long or infinite upstream (with very distinct keys) may lead - * to {@code OutOfMemoryError}. + * to {@link OutOfMemoryError}. *

* Customizing the retention policy can happen only by providing a custom {@link java.util.Collection} implementation * to the {@link #distinct(Function, Supplier)} overload. @@ -7930,23 +8353,24 @@ public final Observable distinct() { * @param keySelector * a function that projects an emitted item to a key value that is used to decide whether an item * is distinct from another one or not - * @return an Observable that emits those items emitted by the source ObservableSource that have distinct keys + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: Distinct * @see #distinct(Function, Supplier) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable distinct(@NonNull Function keySelector) { + public final <@NonNull K> Observable distinct(@NonNull Function keySelector) { return distinct(keySelector, Functions.createHashSet()); } /** - * Returns an Observable that emits all items emitted by the source ObservableSource that are distinct according + * Returns an {@code Observable} that emits all items emitted by the current {@code Observable} that are distinct according * to a key selector function and based on {@link Object#equals(Object)} comparison of the objects * returned by the key selector function. *

- * + * *

* It is recommended the keys' class {@code K} overrides the default {@code Object.equals()} * and {@link Object#hashCode()} to provide meaningful comparison between the key objects as @@ -7961,25 +8385,26 @@ public final Observable distinct(@NonNull Function keySelec * a function that projects an emitted item to a key value that is used to decide whether an item * is distinct from another one or not * @param collectionSupplier - * function called for each individual Observer to return a Collection subtype for holding the extracted - * keys and whose add() method's return indicates uniqueness. - * @return an Observable that emits those items emitted by the source ObservableSource that have distinct keys + * function called for each individual {@link Observer} to return a {@link Collection} subtype for holding the extracted + * keys and whose {@code add()} method's return indicates uniqueness. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code keySelector} or {@code collectionSupplier} is {@code null} * @see ReactiveX operators documentation: Distinct */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable distinct(@NonNull Function keySelector, @NonNull Supplier> collectionSupplier) { + public final <@NonNull K> Observable distinct(@NonNull Function keySelector, @NonNull Supplier> collectionSupplier) { Objects.requireNonNull(keySelector, "keySelector is null"); Objects.requireNonNull(collectionSupplier, "collectionSupplier is null"); return RxJavaPlugins.onAssembly(new ObservableDistinct<>(this, keySelector, collectionSupplier)); } /** - * Returns an Observable that emits all items emitted by the source ObservableSource that are distinct from their + * Returns an {@code Observable} that emits all items emitted by the current {@code Observable} that are distinct from their * immediate predecessors based on {@link Object#equals(Object)} comparison. *

- * + * *

* It is recommended the elements' class {@code T} in the flow overrides the default {@code Object.equals()} to provide * meaningful comparison between items as the default Java implementation only considers reference equivalence. @@ -7992,7 +8417,7 @@ public final Observable distinct(@NonNull Function keySelec *

* Note that if element type {@code T} in the flow is mutable, the comparison of the previous and current * item may yield unexpected results if the items are mutated externally. Common cases are mutable - * {@code CharSequence}s or {@code List}s where the objects will actually have the same + * {@link CharSequence}s or {@link List}s where the objects will actually have the same * references when they are modified and {@code distinctUntilChanged} will evaluate subsequent items as same. * To avoid such situation, it is recommended that mutable data is converted to an immutable one, * for example using {@code map(CharSequence::toString)} or {@code map(list -> Collections.unmodifiableList(new ArrayList<>(list)))}. @@ -8001,8 +8426,7 @@ public final Observable distinct(@NonNull Function keySelec *

{@code distinctUntilChanged} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an Observable that emits those items from the source ObservableSource that are distinct from their - * immediate predecessors + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Distinct * @see #distinctUntilChanged(BiPredicate) */ @@ -8014,11 +8438,11 @@ public final Observable distinctUntilChanged() { } /** - * Returns an Observable that emits all items emitted by the source ObservableSource that are distinct from their + * Returns an {@code Observable} that emits all items emitted by the current {@code Observable} that are distinct from their * immediate predecessors, according to a key selector function and based on {@link Object#equals(Object)} comparison * of those objects returned by the key selector function. *

- * + * *

* It is recommended the keys' class {@code K} overrides the default {@code Object.equals()} to provide * meaningful comparison between the key objects as the default Java implementation only considers reference equivalence. @@ -8032,7 +8456,7 @@ public final Observable distinctUntilChanged() { *

* Note that if element type {@code T} in the flow is mutable, the comparison of the previous and current * item may yield unexpected results if the items are mutated externally. Common cases are mutable - * {@code CharSequence}s or {@code List}s where the objects will actually have the same + * {@link CharSequence}s or {@link List}s where the objects will actually have the same * references when they are modified and {@code distinctUntilChanged} will evaluate subsequent items as same. * To avoid such situation, it is recommended that mutable data is converted to an immutable one, * for example using {@code map(CharSequence::toString)} or {@code map(list -> Collections.unmodifiableList(new ArrayList<>(list)))}. @@ -8045,30 +8469,30 @@ public final Observable distinctUntilChanged() { * @param keySelector * a function that projects an emitted item to a key value that is used to decide whether an item * is distinct from another one or not - * @return an Observable that emits those items from the source ObservableSource whose keys are distinct from - * those of their immediate predecessors + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: Distinct */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable distinctUntilChanged(@NonNull Function keySelector) { + public final <@NonNull K> Observable distinctUntilChanged(@NonNull Function keySelector) { Objects.requireNonNull(keySelector, "keySelector is null"); return RxJavaPlugins.onAssembly(new ObservableDistinctUntilChanged<>(this, keySelector, ObjectHelper.equalsPredicate())); } /** - * Returns an Observable that emits all items emitted by the source ObservableSource that are distinct from their + * Returns an {@code Observable} that emits all items emitted by the current {@code Observable} that are distinct from their * immediate predecessors when compared with each other via the provided comparator function. *

- * + * *

* Note that the operator always retains the latest item from upstream regardless of the comparison result * and uses it in the next comparison with the next upstream item. *

* Note that if element type {@code T} in the flow is mutable, the comparison of the previous and current * item may yield unexpected results if the items are mutated externally. Common cases are mutable - * {@code CharSequence}s or {@code List}s where the objects will actually have the same + * {@link CharSequence}s or {@link List}s where the objects will actually have the same * references when they are modified and {@code distinctUntilChanged} will evaluate subsequent items as same. * To avoid such situation, it is recommended that mutable data is converted to an immutable one, * for example using {@code map(CharSequence::toString)} or {@code map(list -> Collections.unmodifiableList(new ArrayList<>(list)))}. @@ -8078,9 +8502,9 @@ public final Observable distinctUntilChanged(@NonNull Function * * @param comparer the function that receives the previous item and the current item and is - * expected to return true if the two are equal, thus skipping the current value. - * @return an Observable that emits those items from the source ObservableSource that are distinct from their - * immediate predecessors + * expected to return {@code true} if the two are equal, thus skipping the current value. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code comparer} is {@code null} * @see ReactiveX operators documentation: Distinct * @since 2.0 */ @@ -8093,11 +8517,12 @@ public final Observable distinctUntilChanged(@NonNull BiPredicateNote that the {@code onAfterNext} action is shared between subscriptions and as such + * Calls the specified {@link Consumer} with the current item after this item has been emitted to the downstream. + *

+ * Note that the {@code onAfterNext} action is shared between subscriptions and as such * should be thread-safe. *

- * + * *

*
Scheduler:
*
{@code doAfterNext} does not operate by default on a particular {@link Scheduler}.
@@ -8105,8 +8530,9 @@ public final Observable distinctUntilChanged(@NonNull BiPredicateThis operator supports boundary-limited synchronous or asynchronous queue-fusion. *
*

History: 2.0.1 - experimental - * @param onAfterNext the Consumer that will be called after emitting an item from upstream to the downstream - * @return the new Observable instance + * @param onAfterNext the {@code Consumer} that will be called after emitting an item from upstream to the downstream + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onAfterNext} is {@code null} * @since 2.1 */ @CheckReturnValue @@ -8118,39 +8544,39 @@ public final Observable doAfterNext(@NonNull Consumer onAfterNext) } /** - * Registers an {@link Action} to be called when this ObservableSource invokes either + * Registers an {@link Action} to be called when the current {@code Observable} invokes either * {@link Observer#onComplete onComplete} or {@link Observer#onError onError}. *

- * + * *

*
Scheduler:
*
{@code doAfterTerminate} does not operate by default on a particular {@link Scheduler}.
*
* - * @param onFinally - * an {@link Action} to be invoked when the source ObservableSource finishes - * @return an Observable that emits the same items as the source ObservableSource, then invokes the - * {@link Action} + * @param onAfterTerminate + * an {@code Action} to be invoked after the current {@code Observable} finishes + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onAfterTerminate} is {@code null} * @see ReactiveX operators documentation: Do * @see #doOnTerminate(Action) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable doAfterTerminate(@NonNull Action onFinally) { - Objects.requireNonNull(onFinally, "onFinally is null"); - return doOnEach(Functions.emptyConsumer(), Functions.emptyConsumer(), Functions.EMPTY_ACTION, onFinally); + public final Observable doAfterTerminate(@NonNull Action onAfterTerminate) { + Objects.requireNonNull(onAfterTerminate, "onAfterTerminate is null"); + return doOnEach(Functions.emptyConsumer(), Functions.emptyConsumer(), Functions.EMPTY_ACTION, onAfterTerminate); } /** - * Calls the specified action after this Observable signals onError or onCompleted or gets disposed by + * Calls the specified action after the current {@code Observable} signals {@code onError} or {@code onCompleted} or gets disposed by * the downstream. *

In case of a race between a terminal event and a dispose call, the provided {@code onFinally} action * is executed once per subscription. *

Note that the {@code onFinally} action is shared between subscriptions and as such * should be thread-safe. *

- * + * *

*
Scheduler:
*
{@code doFinally} does not operate by default on a particular {@link Scheduler}.
@@ -8158,8 +8584,9 @@ public final Observable doAfterTerminate(@NonNull Action onFinally) { *
This operator supports boundary-limited synchronous or asynchronous queue-fusion.
*
*

History: 2.0.1 - experimental - * @param onFinally the action called when this Observable terminates or gets disposed - * @return the new Observable instance + * @param onFinally the action called when the current {@code Observable} terminates or gets disposed + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onFinally} is {@code null} * @since 2.1 */ @CheckReturnValue @@ -8171,24 +8598,24 @@ public final Observable doFinally(@NonNull Action onFinally) { } /** - * Calls the dispose {@code Action} if the downstream disposes the sequence. + * Calls the given shared {@link Action} if the downstream disposes the sequence. *

* The action is shared between subscriptions and thus may be called concurrently from multiple * threads; the action must be thread safe. *

* If the action throws a runtime exception, that exception is rethrown by the {@code dispose()} call, - * sometimes as a {@code CompositeException} if there were multiple exceptions along the way. + * sometimes as a {@link CompositeException} if there were multiple exceptions along the way. *

- * + * *

*
Scheduler:
*
{@code doOnDispose} does not operate by default on a particular {@link Scheduler}.
*
* * @param onDispose - * the action that gets called when the source {@code ObservableSource}'s Disposable is disposed - * @return the source {@code ObservableSource} modified so as to call this Action when appropriate - * @throws NullPointerException if onDispose is null + * the action that gets called when the current {@code Observable}'s {@link Disposable} is disposed + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onDispose} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -8199,17 +8626,18 @@ public final Observable doOnDispose(@NonNull Action onDispose) { } /** - * Modifies the source ObservableSource so that it invokes an action when it calls {@code onComplete}. + * Returns an {@code Observable} that invokes an {@link Action} when the current {@code Observable} calls {@code onComplete}. *

- * + * *

*
Scheduler:
*
{@code doOnComplete} does not operate by default on a particular {@link Scheduler}.
*
* * @param onComplete - * the action to invoke when the source ObservableSource calls {@code onComplete} - * @return the source ObservableSource with the side-effecting behavior applied + * the action to invoke when the current {@code Observable} calls {@code onComplete} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onComplete} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -8220,16 +8648,21 @@ public final Observable doOnComplete(@NonNull Action onComplete) { } /** - * Calls the appropriate onXXX consumer (shared between all subscribers) whenever a signal with the same type - * passes through, before forwarding them to downstream. + * Calls the appropriate {@code onXXX} consumer (shared between all {@link Observer}s) whenever a signal with the same type + * passes through, before forwarding them to the downstream. *

- * + * *

*
Scheduler:
*
{@code doOnEach} does not operate by default on a particular {@link Scheduler}.
*
* - * @return the source ObservableSource with the side-effecting behavior applied + * @param onNext the {@link Consumer} to invoke when the current {@code Observable} calls {@code onNext} + * @param onError the {@code Consumer} to invoke when the current {@code Observable} calls {@code onError} + * @param onComplete the {@link Action} to invoke when the current {@code Observable} calls {@code onComplete} + * @param onAfterTerminate the {@code Action} to invoke when the current {@code Observable} calls {@code onAfterTerminate} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onNext}, {@code onError}, {@code onComplete} or {@code onAfterTerminate} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -8244,17 +8677,19 @@ private Observable doOnEach(@NonNull Consumer onNext, @NonNull Con } /** - * Modifies the source ObservableSource so that it invokes an action for each item it emits. + * Returns an {@code Observable} that invokes a {@link Consumer} with the appropriate {@link Notification} + * object when the current {@code Observable} signals an item or terminates. *

- * + * *

*
Scheduler:
*
{@code doOnEach} does not operate by default on a particular {@link Scheduler}.
*
* * @param onNotification - * the action to invoke for each item emitted by the source ObservableSource - * @return the source ObservableSource with the side-effecting behavior applied + * the action to invoke for each item emitted by the current {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onNotification} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -8271,23 +8706,25 @@ public final Observable doOnEach(@NonNull Consumer> o } /** - * Modifies the source ObservableSource so that it notifies an Observer for each item and terminal event it emits. + * Returns an {@code Observable} that forwards the items and terminal events of the current + * {@code Observable} to its {@link Observer}s and to the given shared {@code Observer} instance. *

* In case the {@code onError} of the supplied observer throws, the downstream will receive a composite * exception containing the original exception and the exception thrown by {@code onError}. If either the * {@code onNext} or the {@code onComplete} method of the supplied observer throws, the downstream will be * terminated and will receive this thrown exception. *

- * + * *

*
Scheduler:
*
{@code doOnEach} does not operate by default on a particular {@link Scheduler}.
*
* * @param observer - * the observer to be notified about onNext, onError and onComplete events on its - * respective methods before the actual downstream Observer gets notified. - * @return the source ObservableSource with the side-effecting behavior applied + * the observer to be notified about {@code onNext}, {@code onError} and {@code onComplete} events on its + * respective methods before the actual downstream {@code Observer} gets notified. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code observer} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -8303,20 +8740,22 @@ public final Observable doOnEach(@NonNull Observer observer) { } /** - * Modifies the source ObservableSource so that it invokes an action if it calls {@code onError}. + * Calls the given {@link Consumer} with the error {@link Throwable} if the current {@code Observable} failed before forwarding it to + * the downstream. *

* In case the {@code onError} action throws, the downstream will receive a composite exception containing * the original exception and the exception thrown by {@code onError}. *

- * + * *

*
Scheduler:
*
{@code doOnError} does not operate by default on a particular {@link Scheduler}.
*
* * @param onError - * the action to invoke if the source ObservableSource calls {@code onError} - * @return the source ObservableSource with the side-effecting behavior applied + * the action to invoke if the current {@code Observable} calls {@code onError} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onError} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -8327,20 +8766,21 @@ public final Observable doOnError(@NonNull Consumer onErro } /** - * Calls the appropriate onXXX method (shared between all Observer) for the lifecycle events of + * Calls the appropriate {@code onXXX} method (shared between all {@link Observer}s) for the lifecycle events of * the sequence (subscription, disposal). *

- * + * *

*
Scheduler:
*
{@code doOnLifecycle} does not operate by default on a particular {@link Scheduler}.
*
* * @param onSubscribe - * a Consumer called with the Disposable sent via Observer.onSubscribe() + * a {@link Consumer} called with the {@link Disposable} sent via {@link Observer#onSubscribe(Disposable)} * @param onDispose - * called when the downstream disposes the Disposable via dispose() - * @return the source ObservableSource with the side-effecting behavior applied + * called when the downstream disposes the {@code Disposable} via {@code dispose()} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onSubscribe} or {@code onDispose} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -8353,17 +8793,18 @@ public final Observable doOnLifecycle(@NonNull Consumer o } /** - * Modifies the source ObservableSource so that it invokes an action when it calls {@code onNext}. + * Calls the given {@link Consumer} with the value emitted by the current {@code Observable} before forwarding it to the downstream. *

- * + * *

*
Scheduler:
*
{@code doOnNext} does not operate by default on a particular {@link Scheduler}.
*
* * @param onNext - * the action to invoke when the source ObservableSource calls {@code onNext} - * @return the source ObservableSource with the side-effecting behavior applied + * the action to invoke when the current {@code Observable} calls {@code onNext} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onNext} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -8374,20 +8815,21 @@ public final Observable doOnNext(@NonNull Consumer onNext) { } /** - * Modifies the source {@code ObservableSource} so that it invokes the given action when it is subscribed from - * its subscribers. Each subscription will result in an invocation of the given action except when the - * source {@code ObservableSource} is reference counted, in which case the source {@code ObservableSource} will invoke + * Returns an {@code Observable} so that it invokes the given {@link Consumer} when the current {@code Observable} is subscribed from + * its {@link Observer}s. Each subscription will result in an invocation of the given action except when the + * current {@code Observable} is reference counted, in which case the current {@code Observable} will invoke * the given action for the first subscription. *

- * + * *

*
Scheduler:
*
{@code doOnSubscribe} does not operate by default on a particular {@link Scheduler}.
*
* * @param onSubscribe - * the Consumer that gets called when an Observer subscribes to the current {@code Observable} - * @return the source {@code ObservableSource} modified so as to call this Consumer when appropriate + * the {@code Consumer} that gets called when an {@code Observer} subscribes to the current {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onSubscribe} is {@code null} * @see ReactiveX operators documentation: Do */ @CheckReturnValue @@ -8398,7 +8840,7 @@ public final Observable doOnSubscribe(@NonNull Consumer o } /** - * Modifies the source ObservableSource so that it invokes an action when it calls {@code onComplete} or + * Returns an {@code Observable} so that it invokes an action when the current {@code Observable} calls {@code onComplete} or * {@code onError}. *

* @@ -8411,8 +8853,9 @@ public final Observable doOnSubscribe(@NonNull Consumer o *

* * @param onTerminate - * the action to invoke when the source ObservableSource calls {@code onComplete} or {@code onError} - * @return the source ObservableSource with the side-effecting behavior applied + * the action to invoke when the current {@code Observable} calls {@code onComplete} or {@code onError} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onTerminate} is {@code null} * @see ReactiveX operators documentation: Do * @see #doAfterTerminate(Action) */ @@ -8427,8 +8870,8 @@ public final Observable doOnTerminate(@NonNull Action onTerminate) { } /** - * Returns a Maybe that emits the single item at a specified index in a sequence of emissions from - * this Observable or completes if this Observable signals fewer elements than index. + * Returns a {@link Maybe} that emits the single item at a specified index in a sequence of emissions from + * the current {@code Observable} or completes if the current {@code Observable} signals fewer elements than index. *

* *

@@ -8438,10 +8881,9 @@ public final Observable doOnTerminate(@NonNull Action onTerminate) { * * @param index * the zero-based index of the item to retrieve - * @return a Maybe that emits a single item: the item at the specified position in the sequence of - * those emitted by the source ObservableSource + * @return the new {@code Maybe} instance * @throws IndexOutOfBoundsException - * if {@code index} is less than 0 + * if {@code index} is negative * @see ReactiveX operators documentation: ElementAt */ @CheckReturnValue @@ -8455,10 +8897,10 @@ public final Maybe elementAt(long index) { } /** - * Returns a Single that emits the item found at a specified index in a sequence of emissions from - * this Observable, or a default item if that index is out of range. + * Returns a {@link Single} that emits the item found at a specified index in a sequence of emissions from + * the current {@code Observable}, or a default item if that index is out of range. *

- * + * *

*
Scheduler:
*
{@code elementAt} does not operate by default on a particular {@link Scheduler}.
@@ -8468,10 +8910,10 @@ public final Maybe elementAt(long index) { * the zero-based index of the item to retrieve * @param defaultItem * the default item - * @return a Single that emits the item at the specified position in the sequence emitted by the source - * ObservableSource, or the default item if that index is outside the bounds of the source sequence + * @return the new {@code Single} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @throws IndexOutOfBoundsException - * if {@code index} is less than 0 + * if {@code index} is negative * @see ReactiveX operators documentation: ElementAt */ @CheckReturnValue @@ -8486,8 +8928,8 @@ public final Single elementAt(long index, @NonNull T defaultItem) { } /** - * Returns a Single that emits the item found at a specified index in a sequence of emissions from this Observable - * or signals a {@link NoSuchElementException} if this Observable signals fewer elements than index. + * Returns a {@link Single} that emits the item found at a specified index in a sequence of emissions from the current {@code Observable} + * or signals a {@link NoSuchElementException} if the current {@code Observable} signals fewer elements than index. *

* *

@@ -8497,10 +8939,9 @@ public final Single elementAt(long index, @NonNull T defaultItem) { * * @param index * the zero-based index of the item to retrieve - * @return a Single that emits the item at the specified position in the sequence emitted by the source - * ObservableSource, or the default item if that index is outside the bounds of the source sequence + * @return the new {@code Single} instance * @throws IndexOutOfBoundsException - * if {@code index} is less than 0 + * if {@code index} is negative * @see ReactiveX operators documentation: ElementAt */ @CheckReturnValue @@ -8514,19 +8955,19 @@ public final Single elementAtOrError(long index) { } /** - * Filters items emitted by an ObservableSource by only emitting those that satisfy a specified predicate. + * Filters items emitted by the current {@code Observable} by only emitting those that satisfy a specified {@link Predicate}. *

- * + * *

*
Scheduler:
*
{@code filter} does not operate by default on a particular {@link Scheduler}.
*
* * @param predicate - * a function that evaluates each item emitted by the source ObservableSource, returning {@code true} + * a function that evaluates each item emitted by the current {@code Observable}, returning {@code true} * if it passes the filter - * @return an Observable that emits only those items emitted by the source ObservableSource that the filter - * evaluates as {@code true} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @see ReactiveX operators documentation: Filter */ @CheckReturnValue @@ -8538,8 +8979,8 @@ public final Observable filter(@NonNull Predicate predicate) { } /** - * Returns a Maybe that emits only the very first item emitted by the source ObservableSource, or - * completes if the source ObservableSource is empty. + * Returns a {@link Maybe} that emits only the very first item emitted by the current {@code Observable}, or + * completes if the current {@code Observable} is empty. *

* *

@@ -8547,7 +8988,7 @@ public final Observable filter(@NonNull Predicate predicate) { *
{@code firstElement} does not operate by default on a particular {@link Scheduler}.
*
* - * @return the new Maybe instance + * @return the new {@code Maybe} instance * @see ReactiveX operators documentation: First */ @CheckReturnValue @@ -8558,18 +8999,19 @@ public final Maybe firstElement() { } /** - * Returns a Single that emits only the very first item emitted by the source ObservableSource, or a default item - * if the source ObservableSource completes without emitting any items. + * Returns a {@link Single} that emits only the very first item emitted by the current {@code Observable}, or a default item + * if the current {@code Observable} completes without emitting any items. *

- * + * *

*
Scheduler:
*
{@code first} does not operate by default on a particular {@link Scheduler}.
*
* * @param defaultItem - * the default item to emit if the source ObservableSource doesn't emit anything - * @return the new Single instance + * the default item to emit if the current {@code Observable} doesn't emit anything + * @return the new {@code Single} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX operators documentation: First */ @CheckReturnValue @@ -8580,16 +9022,16 @@ public final Single first(@NonNull T defaultItem) { } /** - * Returns a Single that emits only the very first item emitted by this Observable or - * signals a {@link NoSuchElementException} if this Observable is empty. + * Returns a {@link Single} that emits only the very first item emitted by the current {@code Observable} or + * signals a {@link NoSuchElementException} if the current {@code Observable} is empty. *

- * + * *

*
Scheduler:
*
{@code firstOrError} does not operate by default on a particular {@link Scheduler}.
*
* - * @return the new Single instance + * @return the new {@code Single} instance * @see ReactiveX operators documentation: First */ @CheckReturnValue @@ -8600,36 +9042,35 @@ public final Single firstOrError() { } /** - * Returns an Observable that emits items based on applying a function that you supply to each item emitted - * by the source ObservableSource, where that function returns an ObservableSource, and then merging those resulting - * ObservableSources and emitting the results of this merger. + * Returns an {@code Observable} that emits items based on applying a function that you supply to each item emitted + * by the current {@code Observable}, where that function returns an {@link ObservableSource}, and then merging those returned + * {@code ObservableSource}s and emitting the results of this merger. *

- * + * *

*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the value type of the inner ObservableSources and the output type + * @param the value type of the inner {@code ObservableSource}s and the output type * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns an - * ObservableSource - * @return an Observable that emits the result of applying the transformation function to each item emitted - * by the source ObservableSource and merging the results of the ObservableSources obtained from this - * transformation + * a function that, when applied to an item emitted by the current {@code Observable}, returns an + * {@code ObservableSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMap(@NonNull Function> mapper) { + public final <@NonNull R> Observable flatMap(@NonNull Function> mapper) { return flatMap(mapper, false); } /** - * Returns an Observable that emits items based on applying a function that you supply to each item emitted - * by the source ObservableSource, where that function returns an ObservableSource, and then merging those resulting - * ObservableSources and emitting the results of this merger. + * Returns an {@code Observable} that emits items based on applying a function that you supply to each item emitted + * by the current {@code Observable}, where that function returns an {@link ObservableSource}, and then merging those returned + * {@code ObservableSource}s and emitting the results of this merger. *

* *

@@ -8637,92 +9078,91 @@ public final Observable flatMap(@NonNull Function{@code flatMap} does not operate by default on a particular {@link Scheduler}. *
* - * @param the value type of the inner ObservableSources and the output type + * @param the value type of the inner {@code ObservableSource}s and the output type * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns an - * ObservableSource + * a function that, when applied to an item emitted by the current {@code Observable}, returns an + * {@code ObservableSource} * @param delayErrors - * if true, exceptions from the current Observable and all inner ObservableSources are delayed until all of them terminate - * if false, the first one signalling an exception will terminate the whole sequence immediately - * @return an Observable that emits the result of applying the transformation function to each item emitted - * by the source ObservableSource and merging the results of the ObservableSources obtained from this - * transformation + * if {@code true}, exceptions from the current {@code Observable} and all inner {@code ObservableSource}s are delayed until all of them terminate + * if {@code false}, the first one signaling an exception will terminate the whole sequence immediately + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMap(@NonNull Function> mapper, boolean delayErrors) { + public final <@NonNull R> Observable flatMap(@NonNull Function> mapper, boolean delayErrors) { return flatMap(mapper, delayErrors, Integer.MAX_VALUE); } /** - * Returns an Observable that emits items based on applying a function that you supply to each item emitted - * by the source ObservableSource, where that function returns an ObservableSource, and then merging those resulting - * ObservableSources and emitting the results of this merger, while limiting the maximum number of concurrent - * subscriptions to these ObservableSources. + * Returns an {@code Observable} that emits items based on applying a function that you supply to each item emitted + * by the current {@code Observable}, where that function returns an {@link ObservableSource}, and then merging those returned + * {@code ObservableSource}s and emitting the results of this merger, while limiting the maximum number of concurrent + * subscriptions to these {@code ObservableSource}s. *

- * + * *

*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the value type of the inner ObservableSources and the output type + * @param the value type of the inner {@code ObservableSource}s and the output type * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns an - * ObservableSource + * a function that, when applied to an item emitted by the current {@code Observable}, returns an + * {@code ObservableSource} * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently * @param delayErrors - * if true, exceptions from the current Observable and all inner ObservableSources are delayed until all of them terminate - * if false, the first one signalling an exception will terminate the whole sequence immediately - * @return an Observable that emits the result of applying the transformation function to each item emitted - * by the source ObservableSource and merging the results of the ObservableSources obtained from this - * transformation + * if {@code true}, exceptions from the current {@code Observable} and all inner {@code ObservableSource}s are delayed until all of them terminate + * if {@code false}, the first one signaling an exception will terminate the whole sequence immediately + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMap(@NonNull Function> mapper, boolean delayErrors, int maxConcurrency) { + public final <@NonNull R> Observable flatMap(@NonNull Function> mapper, boolean delayErrors, int maxConcurrency) { return flatMap(mapper, delayErrors, maxConcurrency, bufferSize()); } /** - * Returns an Observable that emits items based on applying a function that you supply to each item emitted - * by the source ObservableSource, where that function returns an ObservableSource, and then merging those resulting - * ObservableSources and emitting the results of this merger, while limiting the maximum number of concurrent - * subscriptions to these ObservableSources. + * Returns an {@code Observable} that emits items based on applying a function that you supply to each item emitted + * by the current {@code Observable}, where that function returns an {@link ObservableSource}, and then merging those returned + * {@code ObservableSource}s and emitting the results of this merger, while limiting the maximum number of concurrent + * subscriptions to these {@code ObservableSource}s. *

- * + * *

*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the value type of the inner ObservableSources and the output type + * @param the value type of the inner {@code ObservableSource}s and the output type * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns an - * ObservableSource + * a function that, when applied to an item emitted by the current {@code Observable}, returns an + * {@code ObservableSource} * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently * @param delayErrors - * if true, exceptions from the current Observable and all inner ObservableSources are delayed until all of them terminate - * if false, the first one signalling an exception will terminate the whole sequence immediately + * if {@code true}, exceptions from the current {@code Observable} and all inner {@code ObservableSource}s are delayed until all of them terminate + * if {@code false}, the first one signaling an exception will terminate the whole sequence immediately * @param bufferSize - * the number of elements to prefetch from each inner ObservableSource - * @return an Observable that emits the result of applying the transformation function to each item emitted - * by the source ObservableSource and merging the results of the ObservableSources obtained from this - * transformation + * the number of elements expected from each inner {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMap(@NonNull Function> mapper, + public final <@NonNull R> Observable flatMap(@NonNull Function> mapper, boolean delayErrors, int maxConcurrency, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); @@ -8739,10 +9179,10 @@ public final Observable flatMap(@NonNull Function - * + * *
*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
@@ -8751,21 +9191,21 @@ public final Observable flatMap(@NonNull Function * the result type * @param onNextMapper - * a function that returns an ObservableSource to merge for each item emitted by the source ObservableSource + * a function that returns an {@code ObservableSource} to merge for each item emitted by the current {@code Observable} * @param onErrorMapper - * a function that returns an ObservableSource to merge for an onError notification from the source - * ObservableSource + * a function that returns an {@code ObservableSource} to merge for an {@code onError} notification from the current + * {@code Observable} * @param onCompleteSupplier - * a function that returns an ObservableSource to merge for an onComplete notification from the source - * ObservableSource - * @return an Observable that emits the results of merging the ObservableSources returned from applying the - * specified functions to the emissions and notifications of the source ObservableSource + * a function that returns an {@code ObservableSource} to merge for an {@code onComplete} notification from the current + * {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onNextMapper} or {@code onErrorMapper} or {@code onCompleteSupplier} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMap( + public final <@NonNull R> Observable flatMap( @NonNull Function> onNextMapper, @NonNull Function> onErrorMapper, @NonNull Supplier> onCompleteSupplier) { @@ -8776,11 +9216,11 @@ public final Observable flatMap( } /** - * Returns an Observable that applies a function to each item emitted or notification raised by the source - * ObservableSource and then flattens the ObservableSources returned from these functions and emits the resulting items, - * while limiting the maximum number of concurrent subscriptions to these ObservableSources. + * Returns an {@code Observable} that applies a function to each item emitted or notification raised by the current + * {@code Observable} and then flattens the {@link ObservableSource}s returned from these functions and emits the resulting items, + * while limiting the maximum number of concurrent subscriptions to these {@code ObservableSource}s. *

- * + * *

*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
@@ -8789,24 +9229,25 @@ public final Observable flatMap( * @param * the result type * @param onNextMapper - * a function that returns an ObservableSource to merge for each item emitted by the source ObservableSource + * a function that returns an {@code ObservableSource} to merge for each item emitted by the current {@code Observable} * @param onErrorMapper - * a function that returns an ObservableSource to merge for an onError notification from the source - * ObservableSource + * a function that returns an {@code ObservableSource} to merge for an {@code onError} notification from the current + * {@code Observable} * @param onCompleteSupplier - * a function that returns an ObservableSource to merge for an onComplete notification from the source - * ObservableSource + * a function that returns an {@code ObservableSource} to merge for an {@code onComplete} notification from the current + * {@code Observable} * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently - * @return an Observable that emits the results of merging the ObservableSources returned from applying the - * specified functions to the emissions and notifications of the source ObservableSource + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code onNextMapper} or {@code onErrorMapper} or {@code onCompleteSupplier} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMap( + public final <@NonNull R> Observable flatMap( @NonNull Function> onNextMapper, @NonNull Function> onErrorMapper, @NonNull Supplier> onCompleteSupplier, @@ -8818,175 +9259,177 @@ public final Observable flatMap( } /** - * Returns an Observable that emits items based on applying a function that you supply to each item emitted - * by the source ObservableSource, where that function returns an ObservableSource, and then merging those resulting - * ObservableSources and emitting the results of this merger, while limiting the maximum number of concurrent - * subscriptions to these ObservableSources. + * Returns an {@code Observable} that emits items based on applying a function that you supply to each item emitted + * by the current {@code Observable}, where that function returns an {@link ObservableSource}, and then merging those returned + * {@code ObservableSource}s and emitting the results of this merger, while limiting the maximum number of concurrent + * subscriptions to these {@code ObservableSource}s. *

- * + * *

*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the value type of the inner ObservableSources and the output type + * @param the value type of the inner {@code ObservableSource}s and the output type * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns an - * ObservableSource + * a function that, when applied to an item emitted by the current {@code Observable}, returns an + * {@code ObservableSource} * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently - * @return an Observable that emits the result of applying the transformation function to each item emitted - * by the source ObservableSource and merging the results of the ObservableSources obtained from this - * transformation + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMap(@NonNull Function> mapper, int maxConcurrency) { + public final <@NonNull R> Observable flatMap(@NonNull Function> mapper, int maxConcurrency) { return flatMap(mapper, false, maxConcurrency, bufferSize()); } /** - * Returns an Observable that emits the results of a specified function to the pair of values emitted by the - * source ObservableSource and a specified collection ObservableSource. + * Returns an {@code Observable} that emits the results of a specified function to the pair of values emitted by the + * current {@code Observable} and the mapped inner {@link ObservableSource}. *

- * + * *

*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items emitted by the collection ObservableSource + * the type of items emitted by the collection {@code ObservableSource} * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param mapper - * a function that returns an ObservableSource for each item emitted by the source ObservableSource - * @param resultSelector - * a function that combines one item emitted by each of the source and collection ObservableSources and - * returns an item to be emitted by the resulting ObservableSource - * @return an Observable that emits the results of applying a function to a pair of values emitted by the - * source ObservableSource and the collection ObservableSource + * a function that returns an {@code ObservableSource} for each item emitted by the current {@code Observable} + * @param combiner + * a function that combines one item emitted by each of the source and collection {@code ObservableSource}s and + * returns an item to be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMap(@NonNull Function> mapper, - @NonNull BiFunction resultSelector) { - return flatMap(mapper, resultSelector, false, bufferSize(), bufferSize()); + public final <@NonNull U, @NonNull R> Observable flatMap(@NonNull Function> mapper, + @NonNull BiFunction combiner) { + return flatMap(mapper, combiner, false, bufferSize(), bufferSize()); } /** - * Returns an Observable that emits the results of a specified function to the pair of values emitted by the - * source ObservableSource and a specified collection ObservableSource. + * Returns an {@code Observable} that emits the results of a specified function to the pair of values emitted by the + * current {@code Observable} and the mapped inner {@link ObservableSource}. *

- * + * *

*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items emitted by the collection ObservableSource + * the type of items emitted by the collection {@code ObservableSource} * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param mapper - * a function that returns an ObservableSource for each item emitted by the source ObservableSource + * a function that returns an {@code ObservableSource} for each item emitted by the current {@code Observable} * @param combiner - * a function that combines one item emitted by each of the source and collection ObservableSources and - * returns an item to be emitted by the resulting ObservableSource + * a function that combines one item emitted by each of the source and collection {@code ObservableSource}s and + * returns an item to be emitted by the resulting {@code Observable} * @param delayErrors - * if true, exceptions from the current Observable and all inner ObservableSources are delayed until all of them terminate - * if false, the first one signalling an exception will terminate the whole sequence immediately - * @return an Observable that emits the results of applying a function to a pair of values emitted by the - * source ObservableSource and the collection ObservableSource + * if {@code true}, exceptions from the current {@code Observable} and all inner {@code ObservableSource}s are delayed until all of them terminate + * if {@code false}, the first one signaling an exception will terminate the whole sequence immediately + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMap(@NonNull Function> mapper, + public final <@NonNull U, @NonNull R> Observable flatMap(@NonNull Function> mapper, @NonNull BiFunction combiner, boolean delayErrors) { return flatMap(mapper, combiner, delayErrors, bufferSize(), bufferSize()); } /** - * Returns an Observable that emits the results of a specified function to the pair of values emitted by the - * source ObservableSource and a specified collection ObservableSource, while limiting the maximum number of concurrent - * subscriptions to these ObservableSources. + * Returns an {@code Observable} that emits the results of a specified function to the pair of values emitted by the + * current {@code Observable} and the mapped inner {@link ObservableSource}, while limiting the maximum number of concurrent + * subscriptions to these {@code ObservableSource}s. *

- * + * *

*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items emitted by the collection ObservableSource + * the type of items emitted by the collection {@code ObservableSource} * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param mapper - * a function that returns an ObservableSource for each item emitted by the source ObservableSource + * a function that returns an {@code ObservableSource} for each item emitted by the current {@code Observable} * @param combiner - * a function that combines one item emitted by each of the source and collection ObservableSources and - * returns an item to be emitted by the resulting ObservableSource + * a function that combines one item emitted by each of the source and collection {@code ObservableSource}s and + * returns an item to be emitted by the resulting {@code Observable} * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently * @param delayErrors - * if true, exceptions from the current Observable and all inner ObservableSources are delayed until all of them terminate - * if false, the first one signalling an exception will terminate the whole sequence immediately - * @return an Observable that emits the results of applying a function to a pair of values emitted by the - * source ObservableSource and the collection ObservableSource + * if {@code true}, exceptions from the current {@code Observable} and all inner {@code ObservableSource}s are delayed until all of them terminate + * if {@code false}, the first one signaling an exception will terminate the whole sequence immediately + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMap(@NonNull Function> mapper, + public final <@NonNull U, @NonNull R> Observable flatMap(@NonNull Function> mapper, @NonNull BiFunction combiner, boolean delayErrors, int maxConcurrency) { return flatMap(mapper, combiner, delayErrors, maxConcurrency, bufferSize()); } /** - * Returns an Observable that emits the results of a specified function to the pair of values emitted by the - * source ObservableSource and a specified collection ObservableSource, while limiting the maximum number of concurrent - * subscriptions to these ObservableSources. + * Returns an {@code Observable} that emits the results of a specified function to the pair of values emitted by the + * current {@code Observable} and the mapped inner {@link ObservableSource}, while limiting the maximum number of concurrent + * subscriptions to these {@code ObservableSource}s. *

- * + * *

*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items emitted by the collection ObservableSource + * the type of items emitted by the collection {@code ObservableSource} * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param mapper - * a function that returns an ObservableSource for each item emitted by the source ObservableSource + * a function that returns an {@code ObservableSource} for each item emitted by the current {@code Observable} * @param combiner - * a function that combines one item emitted by each of the source and collection ObservableSources and - * returns an item to be emitted by the resulting ObservableSource + * a function that combines one item emitted by each of the source and collection {@code ObservableSource}s and + * returns an item to be emitted by the resulting {@code Observable} * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently * @param delayErrors - * if true, exceptions from the current Observable and all inner ObservableSources are delayed until all of them terminate - * if false, the first one signalling an exception will terminate the whole sequence immediately + * if {@code true}, exceptions from the current {@code Observable} and all inner {@code ObservableSource}s are delayed until all of them terminate + * if {@code false}, the first one signaling an exception will terminate the whole sequence immediately * @param bufferSize - * the number of elements to prefetch from the inner ObservableSources. - * @return an Observable that emits the results of applying a function to a pair of values emitted by the - * source ObservableSource and the collection ObservableSource + * the number of elements expected from the inner {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMap(@NonNull Function> mapper, + public final <@NonNull U, @NonNull R> Observable flatMap(@NonNull Function> mapper, @NonNull BiFunction combiner, boolean delayErrors, int maxConcurrency, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); Objects.requireNonNull(combiner, "combiner is null"); @@ -8994,51 +9437,53 @@ public final Observable flatMap(@NonNull Function - * + * *
*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items emitted by the collection ObservableSource + * the type of items emitted by the collection {@code ObservableSource} * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param mapper - * a function that returns an ObservableSource for each item emitted by the source ObservableSource + * a function that returns an {@code ObservableSource} for each item emitted by the current {@code Observable} * @param combiner - * a function that combines one item emitted by each of the source and collection ObservableSources and - * returns an item to be emitted by the resulting ObservableSource + * a function that combines one item emitted by each of the source and collection {@code ObservableSource}s and + * returns an item to be emitted by the resulting {@code Observable} * @param maxConcurrency - * the maximum number of ObservableSources that may be subscribed to concurrently - * @return an Observable that emits the results of applying a function to a pair of values emitted by the - * source ObservableSource and the collection ObservableSource + * the maximum number of {@code ObservableSource}s that may be subscribed to concurrently + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMap(@NonNull Function> mapper, + public final <@NonNull U, @NonNull R> Observable flatMap(@NonNull Function> mapper, @NonNull BiFunction combiner, int maxConcurrency) { return flatMap(mapper, combiner, false, maxConcurrency, bufferSize()); } /** - * Maps each element of the upstream Observable into CompletableSources, subscribes to them and - * waits until the upstream and all CompletableSources complete. + * Maps each element of the current {@code Observable} into {@link CompletableSource}s, subscribes to them and + * waits until the upstream and all {@code CompletableSource}s complete. *

* *

*
Scheduler:
*
{@code flatMapCompletable} does not operate by default on a particular {@link Scheduler}.
*
- * @param mapper the function that received each source value and transforms them into CompletableSources. - * @return the new Completable instance + * @param mapper the function that received each source value and transforms them into {@code CompletableSource}s. + * @throws NullPointerException if {@code mapper} is {@code null} + * @return the new {@link Completable} instance */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -9048,18 +9493,19 @@ public final Completable flatMapCompletable(@NonNull Function - * + * *
*
Scheduler:
*
{@code flatMapCompletable} does not operate by default on a particular {@link Scheduler}.
*
- * @param mapper the function that received each source value and transforms them into CompletableSources. - * @param delayErrors if true errors from the upstream and inner CompletableSources are delayed until each of them - * terminates. - * @return the new Completable instance + * @param mapper the function that received each source value and transforms them into {@code CompletableSource}s. + * @param delayErrors if {@code true}, errors from the upstream and inner {@code CompletableSource}s are delayed until all of them + * terminate. + * @return the new {@link Completable} instance + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -9070,8 +9516,8 @@ public final Completable flatMapCompletable(@NonNull Function * *
@@ -9080,25 +9526,27 @@ public final Completable flatMapCompletable(@NonNull Function * * @param - * the type of item emitted by the resulting Iterable + * the output type and the element type of the {@code Iterable}s * @param mapper - * a function that returns an Iterable sequence of values for when given an item emitted by the - * source ObservableSource - * @return an Observable that emits the results of merging the items emitted by the source ObservableSource with - * the values in the Iterables corresponding to those items, as generated by {@code collectionSelector} + * a function that returns an {@code Iterable} sequence of values for when given an item emitted by the + * current {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMapIterable(@NonNull Function> mapper) { + public final <@NonNull U> Observable flatMapIterable(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new ObservableFlattenIterable<>(this, mapper)); } /** - * Returns an Observable that emits the results of applying a function to the pair of values from the source - * ObservableSource and an Iterable corresponding to that item that is generated by a selector. + * Merges {@link Iterable}s generated by a mapper {@link Function} for each individual item emitted by + * the current {@code Observable} into a single {@code Observable} sequence where the resulting items will + * be the combination of the original item and each inner item of the respective {@code Iterable} as returned + * by the {@code resultSelector} {@link BiFunction}. *

* *

@@ -9107,119 +9555,124 @@ public final Observable flatMapIterable(@NonNull Function * * @param - * the collection element type + * the element type of the {@code Iterable}s * @param - * the type of item emitted by the resulting Iterable + * the output type as determined by the {@code resultSelector} function * @param mapper - * a function that returns an Iterable sequence of values for each item emitted by the source - * ObservableSource - * @param resultSelector - * a function that returns an item based on the item emitted by the source ObservableSource and the - * Iterable returned for that item by the {@code collectionSelector} - * @return an Observable that emits the items returned by {@code resultSelector} for each item in the source - * ObservableSource + * a function that returns an {@code Iterable} sequence of values for each item emitted by the current + * {@code Observable} + * @param combiner + * a function that returns an item based on the item emitted by the current {@code Observable} and the + * next item of the {@code Iterable} returned for that original item by the {@code mapper} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMapIterable(@NonNull Function> mapper, - @NonNull BiFunction resultSelector) { + public final <@NonNull U, @NonNull V> Observable flatMapIterable(@NonNull Function> mapper, + @NonNull BiFunction combiner) { Objects.requireNonNull(mapper, "mapper is null"); - Objects.requireNonNull(resultSelector, "resultSelector is null"); - return flatMap(ObservableInternalHelper.flatMapIntoIterable(mapper), resultSelector, false, bufferSize(), bufferSize()); + Objects.requireNonNull(combiner, "combiner is null"); + return flatMap(ObservableInternalHelper.flatMapIntoIterable(mapper), combiner, false, bufferSize(), bufferSize()); } /** - * Maps each element of the upstream Observable into MaybeSources, subscribes to all of them - * and merges their onSuccess values, in no particular order, into a single Observable sequence. + * Maps each element of the current {@code Observable} into {@link MaybeSource}s, subscribes to all of them + * and merges their {@code onSuccess} values, in no particular order, into a single {@code Observable} sequence. *

- * + * *

*
Scheduler:
*
{@code flatMapMaybe} does not operate by default on a particular {@link Scheduler}.
*
* @param the result value type - * @param mapper the function that received each source value and transforms them into MaybeSources. - * @return the new Observable instance + * @param mapper the function that received each source value and transforms them into {@code MaybeSource}s. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMapMaybe(@NonNull Function> mapper) { + public final <@NonNull R> Observable flatMapMaybe(@NonNull Function> mapper) { return flatMapMaybe(mapper, false); } /** - * Maps each element of the upstream Observable into MaybeSources, subscribes to them - * and merges their onSuccess values, in no particular order, into a single Observable sequence, + * Maps each element of the current {@code Observable} into {@link MaybeSource}s, subscribes to them + * and merges their {@code onSuccess} values, in no particular order, into a single {@code Observable} sequence, * optionally delaying all errors. *

- * + * *

*
Scheduler:
*
{@code flatMapMaybe} does not operate by default on a particular {@link Scheduler}.
*
* @param the result value type - * @param mapper the function that received each source value and transforms them into MaybeSources. - * @param delayErrors if true errors from the upstream and inner MaybeSources are delayed until each of them - * terminates. - * @return the new Observable instance + * @param mapper the function that received each source value and transforms them into {@code MaybeSource}s. + * @param delayErrors if {@code true}, errors from the upstream and inner {@code MaybeSource}s are delayed until all of them + * terminate. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMapMaybe(@NonNull Function> mapper, boolean delayErrors) { + public final <@NonNull R> Observable flatMapMaybe(@NonNull Function> mapper, boolean delayErrors) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new ObservableFlatMapMaybe<>(this, mapper, delayErrors)); } /** - * Maps each element of the upstream Observable into SingleSources, subscribes to all of them - * and merges their onSuccess values, in no particular order, into a single Observable sequence. + * Maps each element of the current {@code Observable} into {@link SingleSource}s, subscribes to all of them + * and merges their {@code onSuccess} values, in no particular order, into a single {@code Observable} sequence. *

- * + * *

*
Scheduler:
*
{@code flatMapSingle} does not operate by default on a particular {@link Scheduler}.
*
* @param the result value type - * @param mapper the function that received each source value and transforms them into SingleSources. - * @return the new Observable instance + * @param mapper the function that received each source value and transforms them into {@code SingleSource}s. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMapSingle(@NonNull Function> mapper) { + public final <@NonNull R> Observable flatMapSingle(@NonNull Function> mapper) { return flatMapSingle(mapper, false); } /** - * Maps each element of the upstream Observable into SingleSources, subscribes to them - * and merges their onSuccess values, in no particular order, into a single Observable sequence, + * Maps each element of the current {@code Observable} into {@link SingleSource}s, subscribes to them + * and merges their {@code onSuccess} values, in no particular order, into a single {@code Observable} sequence, * optionally delaying all errors. *

- * + * *

*
Scheduler:
*
{@code flatMapSingle} does not operate by default on a particular {@link Scheduler}.
*
* @param the result value type - * @param mapper the function that received each source value and transforms them into SingleSources. - * @param delayErrors if true errors from the upstream and inner SingleSources are delayed until each of them + * @param mapper the function that received each source value and transforms them into {@code SingleSource}s. + * @param delayErrors if {@code true}, errors from the upstream and inner {@code SingleSource}s are delayed until each of them * terminates. - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable flatMapSingle(@NonNull Function> mapper, boolean delayErrors) { + public final <@NonNull R> Observable flatMapSingle(@NonNull Function> mapper, boolean delayErrors) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new ObservableFlatMapSingle<>(this, mapper, delayErrors)); } /** - * Subscribes to the {@link ObservableSource} and receives notifications for each element. + * Subscribes to the {@link ObservableSource} and calls a {@link Consumer} for each item of the current {@code Observable} + * on its emission thread. *

* *

@@ -9230,11 +9683,11 @@ public final Observable flatMapSingle(@NonNull Function * * @param onNext - * {@link Consumer} to execute for each item. + * the {@code Consumer} to execute for each item. * @return - * a Disposable that allows disposing of an asynchronous sequence + * a {@link Disposable} that allows disposing the sequence if the current {@code Observable} runs asynchronously * @throws NullPointerException - * if {@code onNext} is null + * if {@code onNext} is {@code null} * @see ReactiveX operators documentation: Subscribe */ @CheckReturnValue @@ -9245,25 +9698,25 @@ public final Disposable forEach(@NonNull Consumer onNext) { } /** - * Subscribes to the {@link ObservableSource} and receives notifications for each element until the - * onNext Predicate returns false. + * Subscribes to the {@link ObservableSource} and calls a {@link Predicate} for each item of the current {@code Observable}, + * on its emission thread, until the predicate returns {@code false}. *

- * + * *

- * If the Observable emits an error, it is wrapped into an - * {@link io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException OnErrorNotImplementedException} - * and routed to the RxJavaPlugins.onError handler. + * If the {@code Observable} emits an error, it is wrapped into an + * {@link OnErrorNotImplementedException} + * and routed to the {@link RxJavaPlugins#onError(Throwable)} handler. *

*
Scheduler:
*
{@code forEachWhile} does not operate by default on a particular {@link Scheduler}.
*
* * @param onNext - * {@link Predicate} to execute for each item. + * the {@code Predicate} to execute for each item. * @return - * a Disposable that allows disposing of an asynchronous sequence + * a {@link Disposable} that allows disposing the sequence if the current {@code Observable} runs asynchronously * @throws NullPointerException - * if {@code onNext} is null + * if {@code onNext} is {@code null} * @see ReactiveX operators documentation: Subscribe */ @CheckReturnValue @@ -9274,22 +9727,21 @@ public final Disposable forEachWhile(@NonNull Predicate onNext) { } /** - * Subscribes to the {@link ObservableSource} and receives notifications for each element and error events until the - * onNext Predicate returns false. + * Subscribes to the {@link ObservableSource} and calls a {@link Predicate} for each item or a {@link Consumer} with the error + * of the current {@code Observable}, on their original emission threads, until the predicate returns {@code false}. *
*
Scheduler:
*
{@code forEachWhile} does not operate by default on a particular {@link Scheduler}.
*
* * @param onNext - * {@link Predicate} to execute for each item. + * the {@code Predicate} to execute for each item. * @param onError - * {@link Consumer} to execute when an error is emitted. + * the {@code Consumer} to execute when an error is emitted. * @return - * a Disposable that allows disposing of an asynchronous sequence + * a {@link Disposable} that allows disposing the sequence if the current {@code Observable} runs asynchronously * @throws NullPointerException - * if {@code onNext} is null, or - * if {@code onError} is null + * if {@code onNext} or {@code onError} is {@code null} * @see ReactiveX operators documentation: Subscribe */ @CheckReturnValue @@ -9300,25 +9752,24 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN } /** - * Subscribes to the {@link ObservableSource} and receives notifications for each element and the terminal events until the - * onNext Predicate returns false. + * Subscribes to the {@link ObservableSource} and calls a {@link Predicate} for each item, a {@link Consumer} with the error + * or an {@link Action} upon completion of the current {@code Observable}, on their original emission threads, + * until the predicate returns {@code false}. *
*
Scheduler:
*
{@code forEachWhile} does not operate by default on a particular {@link Scheduler}.
*
* * @param onNext - * {@link Predicate} to execute for each item. + * the {@code Predicate} to execute for each item. * @param onError - * {@link Consumer} to execute when an error is emitted. + * the {@code Consumer} to execute when an error is emitted. * @param onComplete - * {@link Action} to execute when completion is signalled. + * the {@code Action} to execute when completion is signaled. * @return - * a Disposable that allows disposing of an asynchronous sequence + * a {@link Disposable} that allows disposing the sequence if the current {@code Observable} runs asynchronously * @throws NullPointerException - * if {@code onNext} is null, or - * if {@code onError} is null, or - * if {@code onComplete} is null + * if {@code onNext} or {@code onError} or {@code onComplete} is {@code null} * @see ReactiveX operators documentation: Subscribe */ @CheckReturnValue @@ -9336,17 +9787,19 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN } /** - * Groups the items emitted by an {@code ObservableSource} according to a specified criterion, and emits these - * grouped items as {@link GroupedObservable}s. The emitted {@code GroupedObservableSource} allows only a single - * {@link Observer} during its lifetime and if this {@code Observer} calls dispose() before the - * source terminates, the next emission by the source having the same key will trigger a new - * {@code GroupedObservableSource} emission. + * Groups the items emitted by the current {@code Observable} according to a specified criterion, and emits these + * grouped items as {@link GroupedObservable}s. *

- * + * *

- * Note: A {@link GroupedObservable} will cache the items it is to emit until such time as it + * Each emitted {@code GroupedObservable} allows only a single {@link Observer} to subscribe to it during its + * lifetime and if this {@code Observer} calls {@code dispose()} before the + * source terminates, the next emission by the source having the same key will trigger a new + * {@code GroupedObservable} emission. + *

+ * Note: A {@code GroupedObservable} will cache the items it is to emit until such time as it * is subscribed to. For this reason, in order to avoid memory leaks, you should not simply ignore those - * {@code GroupedObservableSource}s that do not concern you. Instead, you can signal to them that they may + * {@code GroupedObservable}s that do not concern you. Instead, you can signal to them that they may * discard their buffers by applying an operator like {@link #ignoreElements} to them. *

* Note also that ignoring groups or subscribing later (i.e., on another thread) will result in @@ -9363,31 +9816,32 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN * a function that extracts the key for each item * @param * the key type - * @return an {@code ObservableSource} that emits {@link GroupedObservable}s, each of which corresponds to a - * unique key value and each of which emits those items from the source ObservableSource that share that - * key value + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: GroupBy */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable> groupBy(@NonNull Function keySelector) { + public final <@NonNull K> Observable> groupBy(@NonNull Function keySelector) { return groupBy(keySelector, (Function)Functions.identity(), false, bufferSize()); } /** - * Groups the items emitted by an {@code ObservableSource} according to a specified criterion, and emits these - * grouped items as {@link GroupedObservable}s. The emitted {@code GroupedObservableSource} allows only a single - * {@link Observer} during its lifetime and if this {@code Observer} calls dispose() before the - * source terminates, the next emission by the source having the same key will trigger a new - * {@code GroupedObservableSource} emission. + * Groups the items emitted by the current {@code Observable} according to a specified criterion, and emits these + * grouped items as {@link GroupedObservable}s. *

- * + * *

- * Note: A {@link GroupedObservable} will cache the items it is to emit until such time as it + * Each emitted {@code GroupedObservable} allows only a single {@link Observer} to subscribe to it during its + * lifetime and if this {@code Observer} calls {@code dispose()} before the + * source terminates, the next emission by the source having the same key will trigger a new + * {@code GroupedObservable} emission. + *

+ * Note: A {@code GroupedObservable} will cache the items it is to emit until such time as it * is subscribed to. For this reason, in order to avoid memory leaks, you should not simply ignore those - * {@code GroupedObservableSource}s that do not concern you. Instead, you can signal to them that they may + * {@code GroupedObservable}s that do not concern you. Instead, you can signal to them that they may * discard their buffers by applying an operator like {@link #ignoreElements} to them. *

* Note also that ignoring groups or subscribing later (i.e., on another thread) will result in @@ -9405,33 +9859,34 @@ public final Observable> groupBy(@NonNull Function * the key type * @param delayError - * if true, the exception from the current Observable is delayed in each group until that specific group emitted - * the normal values; if false, the exception bypasses values in the groups and is reported immediately. - * @return an {@code ObservableSource} that emits {@link GroupedObservable}s, each of which corresponds to a - * unique key value and each of which emits those items from the source ObservableSource that share that - * key value + * if {@code true}, the exception from the current {@code Observable} is delayed in each group until that specific group emitted + * the normal values; if {@code false}, the exception bypasses values in the groups and is reported immediately. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: GroupBy */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable> groupBy(@NonNull Function keySelector, boolean delayError) { + public final <@NonNull K> Observable> groupBy(@NonNull Function keySelector, boolean delayError) { return groupBy(keySelector, (Function)Functions.identity(), delayError, bufferSize()); } /** - * Groups the items emitted by an {@code ObservableSource} according to a specified criterion, and emits these - * grouped items as {@link GroupedObservable}s. The emitted {@code GroupedObservableSource} allows only a single - * {@link Observer} during its lifetime and if this {@code Observer} calls dispose() before the - * source terminates, the next emission by the source having the same key will trigger a new - * {@code GroupedObservableSource} emission. + * Groups the items emitted by the current {@code Observable} according to a specified criterion, and emits these + * grouped items as {@link GroupedObservable}s. *

- * + * *

- * Note: A {@link GroupedObservable} will cache the items it is to emit until such time as it + * Each emitted {@code GroupedObservable} allows only a single {@link Observer} to subscribe to it during its + * lifetime and if this {@code Observer} calls {@code dispose()} before the + * source terminates, the next emission by the source having the same key will trigger a new + * {@code GroupedObservable} emission. + *

+ * Note: A {@code GroupedObservable} will cache the items it is to emit until such time as it * is subscribed to. For this reason, in order to avoid memory leaks, you should not simply ignore those - * {@code GroupedObservableSource}s that do not concern you. Instead, you can signal to them that they may + * {@code GroupedObservable}s that do not concern you. Instead, you can signal to them that they may * discard their buffers by applying an operator like {@link #ignoreElements} to them. *

* Note also that ignoring groups or subscribing later (i.e., on another thread) will result in @@ -9452,31 +9907,32 @@ public final Observable> groupBy(@NonNull Function * the element type - * @return an {@code ObservableSource} that emits {@link GroupedObservable}s, each of which corresponds to a - * unique key value and each of which emits those items from the source ObservableSource that share that - * key value + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code keySelector} or {@code valueSelector} is {@code null} * @see ReactiveX operators documentation: GroupBy */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable> groupBy(@NonNull Function keySelector, + public final <@NonNull K, @NonNull V> Observable> groupBy(@NonNull Function keySelector, Function valueSelector) { return groupBy(keySelector, valueSelector, false, bufferSize()); } /** - * Groups the items emitted by an {@code ObservableSource} according to a specified criterion, and emits these - * grouped items as {@link GroupedObservable}s. The emitted {@code GroupedObservableSource} allows only a single - * {@link Observer} during its lifetime and if this {@code Observer} calls dispose() before the - * source terminates, the next emission by the source having the same key will trigger a new - * {@code GroupedObservableSource} emission. + * Groups the items emitted by the current {@code Observable} according to a specified criterion, and emits these + * grouped items as {@link GroupedObservable}s. *

- * + * *

- * Note: A {@link GroupedObservable} will cache the items it is to emit until such time as it + * Each emitted {@code GroupedObservable} allows only a single {@link Observer} to subscribe to it during its + * lifetime and if this {@code Observer} calls {@code dispose()} before the + * source terminates, the next emission by the source having the same key will trigger a new + * {@code GroupedObservable} emission. + *

+ * Note: A {@code GroupedObservable} will cache the items it is to emit until such time as it * is subscribed to. For this reason, in order to avoid memory leaks, you should not simply ignore those - * {@code GroupedObservableSource}s that do not concern you. Instead, you can signal to them that they may + * {@code GroupedObservable}s that do not concern you. Instead, you can signal to them that they may * discard their buffers by applying an operator like {@link #ignoreElements} to them. *

* Note also that ignoring groups or subscribing later (i.e., on another thread) will result in @@ -9498,33 +9954,34 @@ public final Observable> groupBy(@NonNull Functio * @param * the element type * @param delayError - * if true, the exception from the current Observable is delayed in each group until that specific group emitted - * the normal values; if false, the exception bypasses values in the groups and is reported immediately. - * @return an {@code ObservableSource} that emits {@link GroupedObservable}s, each of which corresponds to a - * unique key value and each of which emits those items from the source ObservableSource that share that - * key value + * if {@code true}, the exception from the current {@code Observable} is delayed in each group until that specific group emitted + * the normal values; if {@code false}, the exception bypasses values in the groups and is reported immediately. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code keySelector} or {@code valueSelector} is {@code null} * @see ReactiveX operators documentation: GroupBy */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable> groupBy(@NonNull Function keySelector, + public final <@NonNull K, @NonNull V> Observable> groupBy(@NonNull Function keySelector, @NonNull Function valueSelector, boolean delayError) { return groupBy(keySelector, valueSelector, delayError, bufferSize()); } /** - * Groups the items emitted by an {@code ObservableSource} according to a specified criterion, and emits these - * grouped items as {@link GroupedObservable}s. The emitted {@code GroupedObservableSource} allows only a single - * {@link Observer} during its lifetime and if this {@code Observer} calls dispose() before the - * source terminates, the next emission by the source having the same key will trigger a new - * {@code GroupedObservableSource} emission. + * Groups the items emitted by the current {@code Observable} according to a specified criterion, and emits these + * grouped items as {@link GroupedObservable}s. *

- * + * *

- * Note: A {@link GroupedObservable} will cache the items it is to emit until such time as it + * Each emitted {@code GroupedObservable} allows only a single {@link Observer} to subscribe to it during its + * lifetime and if this {@code Observer} calls {@code dispose()} before the + * source terminates, the next emission by the source having the same key will trigger a new + * {@code GroupedObservable} emission. + *

+ * Note: A {@code GroupedObservable} will cache the items it is to emit until such time as it * is subscribed to. For this reason, in order to avoid memory leaks, you should not simply ignore those - * {@code GroupedObservableSource}s that do not concern you. Instead, you can signal to them that they may + * {@code GroupedObservable}s that do not concern you. Instead, you can signal to them that they may * discard their buffers by applying an operator like {@link #ignoreElements} to them. *

* Note also that ignoring groups or subscribing later (i.e., on another thread) will result in @@ -9542,23 +9999,23 @@ public final Observable> groupBy(@NonNull Functio * @param valueSelector * a function that extracts the return element for each item * @param delayError - * if true, the exception from the current Observable is delayed in each group until that specific group emitted - * the normal values; if false, the exception bypasses values in the groups and is reported immediately. + * if {@code true}, the exception from the current {@code Observable} is delayed in each group until that specific group emitted + * the normal values; if {@code false}, the exception bypasses values in the groups and is reported immediately. * @param bufferSize - * the hint for how many {@link GroupedObservable}s and element in each {@link GroupedObservable} should be buffered + * the hint for how many {@code GroupedObservable}s and element in each {@code GroupedObservable} should be buffered * @param * the key type * @param * the element type - * @return an {@code ObservableSource} that emits {@link GroupedObservable}s, each of which corresponds to a - * unique key value and each of which emits those items from the source ObservableSource that share that - * key value + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code keySelector} or {@code valueSelector} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: GroupBy */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable> groupBy(@NonNull Function keySelector, + public final <@NonNull K, @NonNull V> Observable> groupBy(@NonNull Function keySelector, @NonNull Function valueSelector, boolean delayError, int bufferSize) { Objects.requireNonNull(keySelector, "keySelector is null"); @@ -9569,40 +10026,40 @@ public final Observable> groupBy(@NonNull Functio } /** - * Returns an Observable that correlates two ObservableSources when they overlap in time and groups the results. + * Returns an {@code Observable} that correlates two {@link ObservableSource}s when they overlap in time and groups the results. *

* There are no guarantees in what order the items get combined when multiple - * items from one or both source ObservableSources overlap. + * items from one or both source {@code ObservableSource}s overlap. *

- * + * *

*
Scheduler:
*
{@code groupJoin} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the value type of the right ObservableSource source - * @param the element type of the left duration ObservableSources - * @param the element type of the right duration ObservableSources + * @param the value type of the right {@code ObservableSource} source + * @param the element type of the left duration {@code ObservableSource}s + * @param the element type of the right duration {@code ObservableSource}s * @param the result type * @param other - * the other ObservableSource to correlate items from the source ObservableSource with + * the other {@code ObservableSource} to correlate items from the current {@code Observable} with * @param leftEnd - * a function that returns an ObservableSource whose emissions indicate the duration of the values of - * the source ObservableSource + * a function that returns an {@code ObservableSource} whose emissions indicate the duration of the values of + * the current {@code Observable} * @param rightEnd - * a function that returns an ObservableSource whose emissions indicate the duration of the values of - * the {@code right} ObservableSource + * a function that returns an {@code ObservableSource} whose emissions indicate the duration of the values of + * the {@code right} {@code ObservableSource} * @param resultSelector - * a function that takes an item emitted by each ObservableSource and returns the value to be emitted - * by the resulting ObservableSource - * @return an Observable that emits items based on combining those items emitted by the source ObservableSources - * whose durations overlap + * a function that takes an item emitted by each {@code ObservableSource} and returns the value to be emitted + * by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other}, {@code leftEnd}, {@code rightEnd} or {@code resultSelector} is {@code null} * @see ReactiveX operators documentation: Join */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable groupJoin( + public final <@NonNull TRight, @NonNull TLeftEnd, @NonNull TRightEnd, @NonNull R> Observable groupJoin( @NonNull ObservableSource other, @NonNull Function> leftEnd, @NonNull Function> rightEnd, @@ -9617,8 +10074,9 @@ public final Observable groupJoin( } /** - * Hides the identity of this Observable and its Disposable. - *

Allows hiding extra features such as {@link io.reactivex.rxjava3.subjects.Subject}'s + * Hides the identity of the current {@code Observable} and its {@link Disposable}. + *

+ * Allows hiding extra features such as {@link io.reactivex.rxjava3.subjects.Subject}'s * {@link Observer} methods or preventing certain identity-based * optimizations (fusion). *

@@ -9627,7 +10085,7 @@ public final Observable groupJoin( *

Scheduler:
*
{@code hide} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new Observable instance + * @return the new {@code Observable} instance * * @since 2.0 */ @@ -9639,15 +10097,15 @@ public final Observable hide() { } /** - * Ignores all items emitted by the source ObservableSource and only calls {@code onComplete} or {@code onError}. + * Ignores all items emitted by the current {@code Observable} and only calls {@code onComplete} or {@code onError}. *

- * + * *

*
Scheduler:
*
{@code ignoreElements} does not operate by default on a particular {@link Scheduler}.
*
* - * @return the new Completable instance + * @return the new {@link Completable} instance * @see ReactiveX operators documentation: IgnoreElements */ @CheckReturnValue @@ -9658,18 +10116,18 @@ public final Completable ignoreElements() { } /** - * Returns a Single that emits {@code true} if the source ObservableSource is empty, otherwise {@code false}. + * Returns a {@link Single} that emits {@code true} if the current {@code Observable} is empty, otherwise {@code false}. *

- * In Rx.Net this is negated as the {@code any} Observer but we renamed this in RxJava to better match Java + * In Rx.Net this is negated as the {@code any} {@link Observer} but we renamed this in RxJava to better match Java * naming idioms. *

- * + * *

*
Scheduler:
*
{@code isEmpty} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a Single that emits a Boolean + * @return the new {@code Single} instance * @see ReactiveX operators documentation: Contains */ @CheckReturnValue @@ -9680,40 +10138,40 @@ public final Single isEmpty() { } /** - * Correlates the items emitted by two ObservableSources based on overlapping durations. + * Correlates the items emitted by two {@link ObservableSource}s based on overlapping durations. *

* There are no guarantees in what order the items get combined when multiple - * items from one or both source ObservableSources overlap. + * items from one or both source {@code ObservableSource}s overlap. *

- * + * *

*
Scheduler:
*
{@code join} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the value type of the right ObservableSource source - * @param the element type of the left duration ObservableSources - * @param the element type of the right duration ObservableSources + * @param the value type of the right {@code ObservableSource} source + * @param the element type of the left duration {@code ObservableSource}s + * @param the element type of the right duration {@code ObservableSource}s * @param the result type * @param other - * the second ObservableSource to join items from + * the second {@code ObservableSource} to join items from * @param leftEnd - * a function to select a duration for each item emitted by the source ObservableSource, used to + * a function to select a duration for each item emitted by the current {@code Observable}, used to * determine overlap * @param rightEnd - * a function to select a duration for each item emitted by the {@code right} ObservableSource, used to + * a function to select a duration for each item emitted by the {@code right} {@code ObservableSource}, used to * determine overlap * @param resultSelector - * a function that computes an item to be emitted by the resulting ObservableSource for any two - * overlapping items emitted by the two ObservableSources - * @return an Observable that emits items correlating to items emitted by the source ObservableSources that have - * overlapping durations + * a function that computes an item to be emitted by the resulting {@code Observable} for any two + * overlapping items emitted by the two {@code ObservableSource}s + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other}, {@code leftEnd}, {@code rightEnd} or {@code resultSelector} is {@code null} * @see ReactiveX operators documentation: Join */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable join( + public final <@NonNull TRight, @NonNull TLeftEnd, @NonNull TRightEnd, @NonNull R> Observable join( @NonNull ObservableSource other, @NonNull Function> leftEnd, @NonNull Function> rightEnd, @@ -9728,17 +10186,16 @@ public final Observable join( } /** - * Returns a Maybe that emits the last item emitted by this Observable or - * completes if this Observable is empty. + * Returns a {@link Maybe} that emits the last item emitted by the current {@code Observable} or + * completes if the current {@code Observable} is empty. *

- * + * *

*
Scheduler:
*
{@code lastElement} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a Maybe that emits the last item from the source ObservableSource or notifies observers of an - * error + * @return the new {@code Maybe} instance * @see ReactiveX operators documentation: Last */ @CheckReturnValue @@ -9749,19 +10206,19 @@ public final Maybe lastElement() { } /** - * Returns a Single that emits only the last item emitted by this Observable, or a default item - * if this Observable completes without emitting any items. + * Returns a {@link Single} that emits only the last item emitted by the current {@code Observable}, or a default item + * if the current {@code Observable} completes without emitting any items. *

- * + * *

*
Scheduler:
*
{@code last} does not operate by default on a particular {@link Scheduler}.
*
* * @param defaultItem - * the default item to emit if the source ObservableSource is empty - * @return a Single that emits only the last item emitted by the source ObservableSource, or a default item - * if the source ObservableSource is empty + * the default item to emit if the current {@code Observable} is empty + * @return the new {@code Single} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX operators documentation: Last */ @CheckReturnValue @@ -9773,8 +10230,8 @@ public final Single last(@NonNull T defaultItem) { } /** - * Returns a Single that emits only the last item emitted by this Observable or - * signals a {@link NoSuchElementException} if this Observable is empty. + * Returns a {@link Single} that emits only the last item emitted by the current {@code Observable} or + * signals a {@link NoSuchElementException} if the current {@code Observable} is empty. *

* *

@@ -9782,8 +10239,7 @@ public final Single last(@NonNull T defaultItem) { *
{@code lastOrError} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a Single that emits only the last item emitted by the source ObservableSource. - * If the source ObservableSource completes without emitting any items a {@link NoSuchElementException} will be thrown. + * @return the new {@code Single} instance * @see ReactiveX operators documentation: Last */ @CheckReturnValue @@ -9798,7 +10254,7 @@ public final Single lastOrError() { * other standard composition methods first; * Returns an {@code Observable} which, when subscribed to, invokes the {@link ObservableOperator#apply(Observer) apply(Observer)} method * of the provided {@link ObservableOperator} for each individual downstream {@link Observer} and allows the - * insertion of a custom operator by accessing the downstream's {@link Observer} during this subscription phase + * insertion of a custom operator by accessing the downstream's {@code Observer} during this subscription phase * and providing a new {@code Observer}, containing the custom operator's intended business logic, that will be * used in the subscription process going further upstream. *

@@ -9915,39 +10371,40 @@ public final Single lastOrError() { * class and creating an {@link ObservableTransformer} with it is recommended. *

* Note also that it is not possible to stop the subscription phase in {@code lift()} as the {@code apply()} method - * requires a non-null {@code Observer} instance to be returned, which is then unconditionally subscribed to - * the upstream {@code Observable}. For example, if the operator decided there is no reason to subscribe to the + * requires a non-{@code null} {@code Observer} instance to be returned, which is then unconditionally subscribed to + * the current {@code Observable}. For example, if the operator decided there is no reason to subscribe to the * upstream source because of some optimization possibility or a failure to prepare the operator, it still has to - * return an {@code Observer} that should immediately dispose the upstream's {@code Disposable} in its + * return an {@code Observer} that should immediately dispose the upstream's {@link Disposable} in its * {@code onSubscribe} method. Again, using an {@code ObservableTransformer} and extending the {@code Observable} is * a better option as {@link #subscribeActual} can decide to not subscribe to its upstream after all. *

*
Scheduler:
*
{@code lift} does not operate by default on a particular {@link Scheduler}, however, the - * {@link ObservableOperator} may use a {@code Scheduler} to support its own asynchronous behavior.
+ * {@code ObservableOperator} may use a {@code Scheduler} to support its own asynchronous behavior. *
* * @param the output value type - * @param lifter the {@link ObservableOperator} that receives the downstream's {@code Observer} and should return + * @param lifter the {@code ObservableOperator} that receives the downstream's {@code Observer} and should return * an {@code Observer} with custom behavior to be used as the consumer for the current * {@code Observable}. - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code lifter} is {@code null} * @see RxJava wiki: Writing operators * @see #compose(ObservableTransformer) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable lift(@NonNull ObservableOperator lifter) { + public final <@NonNull R> Observable lift(@NonNull ObservableOperator lifter) { Objects.requireNonNull(lifter, "lifter is null"); return RxJavaPlugins.onAssembly(new ObservableLift<>(this, lifter)); } /** - * Returns an Observable that applies a specified function to each item emitted by the source ObservableSource and + * Returns an {@code Observable} that applies a specified function to each item emitted by the current {@code Observable} and * emits the results of these function applications. *

- * + * *

*
Scheduler:
*
{@code map} does not operate by default on a particular {@link Scheduler}.
@@ -9955,31 +10412,30 @@ public final Observable lift(@NonNull ObservableOperator the output type * @param mapper - * a function to apply to each item emitted by the ObservableSource - * @return an Observable that emits the items from the source ObservableSource, transformed by the specified - * function + * a function to apply to each item emitted by the current {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: Map */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable map(@NonNull Function mapper) { + public final <@NonNull R> Observable map(@NonNull Function mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new ObservableMap<>(this, mapper)); } /** - * Returns an Observable that represents all of the emissions and notifications from the source - * ObservableSource into emissions marked with their original types within {@link Notification} objects. + * Returns an {@code Observable} that represents all of the emissions and notifications from the current + * {@code Observable} into emissions marked with their original types within {@link Notification} objects. *

- * + * *

*
Scheduler:
*
{@code materialize} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an Observable that emits items that are the result of materializing the items and notifications - * of the source ObservableSource + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Materialize * @see #dematerialize(Function) */ @@ -9991,11 +10447,11 @@ public final Observable> materialize() { } /** - * Flattens this and another ObservableSource into a single ObservableSource, without any transformation. + * Flattens the current {@code Observable} and another {@link ObservableSource} into a single {@code Observable} sequence, without any transformation. *

- * + * *

- * You can combine items emitted by multiple ObservableSources so that they appear as a single ObservableSource, by + * You can combine items emitted by multiple {@code ObservableSource}s so that they appear as a single {@code ObservableSource}, by * using the {@code mergeWith} method. *

*
Scheduler:
@@ -10003,8 +10459,9 @@ public final Observable> materialize() { *
* * @param other - * an ObservableSource to be merged - * @return an Observable that emits all of the items emitted by the source ObservableSources + * an {@code ObservableSource} to be merged + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: Merge */ @CheckReturnValue @@ -10016,11 +10473,11 @@ public final Observable mergeWith(@NonNull ObservableSource othe } /** - * Merges the sequence of items of this Observable with the success value of the other SingleSource. + * Merges the sequence of items of the current {@code Observable} with the success value of the other {@link SingleSource}. *

- * + * *

- * The success value of the other {@code SingleSource} can get interleaved at any point of this + * The success value of the other {@code SingleSource} can get interleaved at any point of the current * {@code Observable} sequence. *

*
Scheduler:
@@ -10028,7 +10485,8 @@ public final Observable mergeWith(@NonNull ObservableSource othe *
*

History: 2.1.10 - experimental * @param other the {@code SingleSource} whose success value to merge with - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -10040,12 +10498,12 @@ public final Observable mergeWith(@NonNull SingleSource other) { } /** - * Merges the sequence of items of this Observable with the success value of the other MaybeSource - * or waits both to complete normally if the MaybeSource is empty. + * Merges the sequence of items of the current {@code Observable} with the success value of the other {@link MaybeSource} + * or waits both to complete normally if the {@code MaybeSource} is empty. *

- * + * *

- * The success value of the other {@code MaybeSource} can get interleaved at any point of this + * The success value of the other {@code MaybeSource} can get interleaved at any point of the current * {@code Observable} sequence. *

*
Scheduler:
@@ -10053,7 +10511,8 @@ public final Observable mergeWith(@NonNull SingleSource other) { *
*

History: 2.1.10 - experimental * @param other the {@code MaybeSource} which provides a success value to merge with or completes - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -10065,17 +10524,18 @@ public final Observable mergeWith(@NonNull MaybeSource other) { } /** - * Relays the items of this Observable and completes only when the other CompletableSource completes + * Relays the items of the current {@code Observable} and completes only when the other {@link CompletableSource} completes * as well. *

- * + * *

*
Scheduler:
*
{@code mergeWith} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.1.10 - experimental * @param other the {@code CompletableSource} to await for completion - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -10087,29 +10547,29 @@ public final Observable mergeWith(@NonNull CompletableSource other) { } /** - * Modifies an ObservableSource to perform its emissions and notifications on a specified {@link Scheduler}, + * Returns an {@code Observable} to perform the current {@code Observable}'s emissions and notifications on a specified {@link Scheduler}, * asynchronously with an unbounded buffer with {@link Flowable#bufferSize()} "island size". * - *

Note that onError notifications will cut ahead of onNext notifications on the emission thread if Scheduler is truly + *

Note that {@code onError} notifications will cut ahead of {@code onNext} notifications on the emission thread if {@code Scheduler} is truly * asynchronous. If strict event ordering is required, consider using the {@link #observeOn(Scheduler, boolean)} overload. *

- * + * *

- * This operator keeps emitting as many signals as it can on the given Scheduler's Worker thread, + * This operator keeps emitting as many signals as it can on the given {@code Scheduler}'s worker thread, * which may result in a longer than expected occupation of this thread. In other terms, * it does not allow per-signal fairness in case the worker runs on a shared underlying thread. * If such fairness and signal/work interleaving is preferred, use the delay operator with zero time instead. *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
*

"Island size" indicates how large chunks the unbounded buffer allocates to store the excess elements waiting to be consumed * on the other side of the asynchronous boundary. * * @param scheduler - * the {@link Scheduler} to notify {@link Observer}s on - * @return the source ObservableSource modified so that its {@link Observer}s are notified on the specified - * {@link Scheduler} + * the {@code Scheduler} to notify {@link Observer}s on + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: ObserveOn * @see RxJava Threading Examples * @see #subscribeOn @@ -10125,30 +10585,30 @@ public final Observable observeOn(@NonNull Scheduler scheduler) { } /** - * Modifies an ObservableSource to perform its emissions and notifications on a specified {@link Scheduler}, - * asynchronously with an unbounded buffer with {@link Flowable#bufferSize()} "island size" and optionally delays onError notifications. + * Returns an {@code Observable} to perform the current {@code Observable}'s emissions and notifications on a specified {@link Scheduler}, + * asynchronously with an unbounded buffer with {@link Flowable#bufferSize()} "island size" and optionally delays {@code onError} notifications. *

- * + * *

- * This operator keeps emitting as many signals as it can on the given Scheduler's Worker thread, + * This operator keeps emitting as many signals as it can on the given {@code Scheduler}'s worker thread, * which may result in a longer than expected occupation of this thread. In other terms, * it does not allow per-signal fairness in case the worker runs on a shared underlying thread. * If such fairness and signal/work interleaving is preferred, use the delay operator with zero time instead. *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
*

"Island size" indicates how large chunks the unbounded buffer allocates to store the excess elements waiting to be consumed * on the other side of the asynchronous boundary. * * @param scheduler - * the {@link Scheduler} to notify {@link Observer}s on + * the {@code Scheduler} to notify {@link Observer}s on * @param delayError - * indicates if the onError notification may not cut ahead of onNext notification on the other side of the - * scheduling boundary. If true a sequence ending in onError will be replayed in the same order as was received - * from upstream - * @return the source ObservableSource modified so that its {@link Observer}s are notified on the specified - * {@link Scheduler} + * indicates if the {@code onError} notification may not cut ahead of {@code onNext} notification on the other side of the + * scheduling boundary. If {@code true}, a sequence ending in {@code onError} will be replayed in the same order as was received + * from the current {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: ObserveOn * @see RxJava Threading Examples * @see #subscribeOn @@ -10164,31 +10624,32 @@ public final Observable observeOn(@NonNull Scheduler scheduler, boolean delay } /** - * Modifies an ObservableSource to perform its emissions and notifications on a specified {@link Scheduler}, - * asynchronously with an unbounded buffer of configurable "island size" and optionally delays onError notifications. + * Returns an {@code Observable} to perform the current {@code Observable}'s emissions and notifications on a specified {@link Scheduler}, + * asynchronously with an unbounded buffer of configurable "island size" and optionally delays {@code onError} notifications. *

- * + * *

- * This operator keeps emitting as many signals as it can on the given Scheduler's Worker thread, + * This operator keeps emitting as many signals as it can on the given {@code Scheduler}'s worker thread, * which may result in a longer than expected occupation of this thread. In other terms, * it does not allow per-signal fairness in case the worker runs on a shared underlying thread. * If such fairness and signal/work interleaving is preferred, use the delay operator with zero time instead. *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
*

"Island size" indicates how large chunks the unbounded buffer allocates to store the excess elements waiting to be consumed * on the other side of the asynchronous boundary. Values below 16 are not recommended in performance sensitive scenarios. * * @param scheduler - * the {@link Scheduler} to notify {@link Observer}s on + * the {@code Scheduler} to notify {@link Observer}s on * @param delayError - * indicates if the onError notification may not cut ahead of onNext notification on the other side of the - * scheduling boundary. If true a sequence ending in onError will be replayed in the same order as was received + * indicates if the {@code onError} notification may not cut ahead of {@code onNext} notification on the other side of the + * scheduling boundary. If {@code true} a sequence ending in {@code onError} will be replayed in the same order as was received * from upstream * @param bufferSize the size of the buffer. - * @return the source ObservableSource modified so that its {@link Observer}s are notified on the specified - * {@link Scheduler} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: ObserveOn * @see RxJava Threading Examples * @see #subscribeOn @@ -10206,9 +10667,9 @@ public final Observable observeOn(@NonNull Scheduler scheduler, boolean delay } /** - * Filters the items emitted by an ObservableSource, only emitting those of the specified type. + * Filters the items emitted by the current {@code Observable}, only emitting those of the specified type. *

- * + * *

*
Scheduler:
*
{@code ofType} does not operate by default on a particular {@link Scheduler}.
@@ -10216,32 +10677,76 @@ public final Observable observeOn(@NonNull Scheduler scheduler, boolean delay * * @param the output type * @param clazz - * the class type to filter the items emitted by the source ObservableSource - * @return an Observable that emits items from the source ObservableSource of type {@code clazz} + * the class type to filter the items emitted by the current {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code clazz} is {@code null} * @see ReactiveX operators documentation: Filter */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable ofType(@NonNull Class clazz) { + public final <@NonNull U> Observable ofType(@NonNull Class clazz) { Objects.requireNonNull(clazz, "clazz is null"); return filter(Functions.isInstanceOf(clazz)).cast(clazz); } /** - * Instructs an ObservableSource to pass control to another ObservableSource rather than invoking - * {@link Observer#onError onError} if it encounters an error. + * Returns an {@code Observable} instance that if the current {@code Observable} emits an error, it will emit an {@code onComplete} + * and swallow the throwable. *

- * + * + *

+ *
Scheduler:
+ *
{@code onErrorComplete} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @return the new {@code Observable} instance + * @since 3.0.0 + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Observable onErrorComplete() { + return onErrorComplete(Functions.alwaysTrue()); + } + + /** + * Returns an {@code Observable} instance that if the current {@code Observable} emits an error and the predicate returns + * {@code true}, it will emit an {@code onComplete} and swallow the throwable. *

- * By default, when an ObservableSource encounters an error that prevents it from emitting the expected item to - * its {@link Observer}, the ObservableSource invokes its Observer's {@code onError} method, and then quits - * without invoking any more of its Observer's methods. The {@code onErrorResumeNext} method changes this - * behavior. If you pass a function that returns an ObservableSource ({@code resumeFunction}) to - * {@code onErrorResumeNext}, if the original ObservableSource encounters an error, instead of invoking its - * Observer's {@code onError} method, it will instead relinquish control to the ObservableSource returned from - * {@code resumeFunction}, which will invoke the Observer's {@link Observer#onNext onNext} method if it is - * able to do so. In such a case, because no ObservableSource necessarily invokes {@code onError}, the Observer + * + *

+ *
Scheduler:
+ *
{@code onErrorComplete} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param predicate the predicate to call when an {@link Throwable} is emitted which should return {@code true} + * if the {@code Throwable} should be swallowed and replaced with an {@code onComplete}. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code predicate} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final Observable onErrorComplete(@NonNull Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + + return RxJavaPlugins.onAssembly(new ObservableOnErrorComplete<>(this, predicate)); + } + + /** + * Resumes the flow with an {@link ObservableSource} returned for the failure {@link Throwable} of the current {@code Observable} by a + * function instead of signaling the error via {@code onError}. + *

+ * + *

+ * By default, when an {@code ObservableSource} encounters an error that prevents it from emitting the expected item to + * its {@link Observer}, the {@code ObservableSource} invokes its {@code Observer}'s {@code onError} method, and then quits + * without invoking any more of its {@code Observer}'s methods. The {@code onErrorResumeNext} method changes this + * behavior. If you pass a function that returns an {@code ObservableSource} ({@code resumeFunction}) to + * {@code onErrorResumeNext}, if the original {@code ObservableSource} encounters an error, instead of invoking its + * {@code Observer}'s {@code onError} method, it will instead relinquish control to the {@code ObservableSource} returned from + * {@code resumeFunction}, which will invoke the {@code Observer}'s {@link Observer#onNext onNext} method if it is + * able to do so. In such a case, because no {@code ObservableSource} necessarily invokes {@code onError}, the {@code Observer} * may never know that an error happened. *

* You can use this to prevent errors from propagating or to supply fallback data should errors be @@ -10251,34 +10756,35 @@ public final Observable ofType(@NonNull Class clazz) { *

{@code onErrorResumeNext} does not operate by default on a particular {@link Scheduler}.
*
* - * @param resumeFunction - * a function that returns an ObservableSource that will take over if the source ObservableSource encounters + * @param fallbackSupplier + * a function that returns an {@code ObservableSource} that will take over if the current {@code Observable} encounters * an error - * @return the original ObservableSource, with appropriately modified behavior + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code fallbackSupplier} is {@code null} * @see ReactiveX operators documentation: Catch */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable onErrorResumeNext(@NonNull Function> resumeFunction) { - Objects.requireNonNull(resumeFunction, "resumeFunction is null"); - return RxJavaPlugins.onAssembly(new ObservableOnErrorNext<>(this, resumeFunction)); + public final Observable onErrorResumeNext(@NonNull Function> fallbackSupplier) { + Objects.requireNonNull(fallbackSupplier, "fallbackSupplier is null"); + return RxJavaPlugins.onAssembly(new ObservableOnErrorNext<>(this, fallbackSupplier)); } /** - * Instructs an ObservableSource to pass control to another ObservableSource rather than invoking - * {@link Observer#onError onError} if it encounters an error. + * Resumes the flow with the given {@link ObservableSource} when the current {@code Observable} fails instead of + * signaling the error via {@code onError}. *

- * + * *

- * By default, when an ObservableSource encounters an error that prevents it from emitting the expected item to - * its {@link Observer}, the ObservableSource invokes its Observer's {@code onError} method, and then quits - * without invoking any more of its Observer's methods. The {@code onErrorResumeWith} method changes this - * behavior. If you pass another ObservableSource ({@code next}) to an ObservableSource's - * {@code onErrorResumeWith} method, if the original ObservableSource encounters an error, instead of invoking its - * Observer's {@code onError} method, it will instead relinquish control to {@code next} which - * will invoke the Observer's {@link Observer#onNext onNext} method if it is able to do so. In such a case, - * because no ObservableSource necessarily invokes {@code onError}, the Observer may never know that an error + * By default, when an {@code ObservableSource} encounters an error that prevents it from emitting the expected item to + * its {@link Observer}, the {@code ObservableSource} invokes its {@code Observer}'s {@code onError} method, and then quits + * without invoking any more of its {@code Observer}'s methods. The {@code onErrorResumeWith} method changes this + * behavior. If you pass another {@code ObservableSource} ({@code next}) to an {@code ObservableSource}'s + * {@code onErrorResumeWith} method, if the original {@code ObservableSource} encounters an error, instead of invoking its + * {@code Observer}'s {@code onError} method, it will instead relinquish control to {@code next} which + * will invoke the {@code Observer}'s {@link Observer#onNext onNext} method if it is able to do so. In such a case, + * because no {@code ObservableSource} necessarily invokes {@code onError}, the {@code Observer} may never know that an error * happened. *

* You can use this to prevent errors from propagating or to supply fallback data should errors be @@ -10288,31 +10794,32 @@ public final Observable onErrorResumeNext(@NonNull Function{@code onErrorResumeWith} does not operate by default on a particular {@link Scheduler}. *

* - * @param next - * the next ObservableSource source that will take over if the source ObservableSource encounters + * @param fallback + * the next {@code ObservableSource} source that will take over if the current {@code Observable} encounters * an error - * @return the original ObservableSource, with appropriately modified behavior + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code fallback} is {@code null} * @see ReactiveX operators documentation: Catch */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable onErrorResumeWith(@NonNull ObservableSource next) { - Objects.requireNonNull(next, "next is null"); - return onErrorResumeNext(Functions.justFunction(next)); + public final Observable onErrorResumeWith(@NonNull ObservableSource fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return onErrorResumeNext(Functions.justFunction(fallback)); } /** - * Instructs an ObservableSource to emit an item (returned by a specified function) rather than invoking - * {@link Observer#onError onError} if it encounters an error. + * Ends the flow with a last item returned by a function for the {@link Throwable} error signaled by the current + * {@code Observable} instead of signaling the error via {@code onError}. *

- * + * *

- * By default, when an ObservableSource encounters an error that prevents it from emitting the expected item to - * its {@link Observer}, the ObservableSource invokes its Observer's {@code onError} method, and then quits - * without invoking any more of its Observer's methods. The {@code onErrorReturn} method changes this - * behavior. If you pass a function ({@code resumeFunction}) to an ObservableSource's {@code onErrorReturn} - * method, if the original ObservableSource encounters an error, instead of invoking its Observer's + * By default, when an {@link ObservableSource} encounters an error that prevents it from emitting the expected item to + * its {@link Observer}, the {@code ObservableSource} invokes its {@code Observer}'s {@code onError} method, and then quits + * without invoking any more of its {@code Observer}'s methods. The {@code onErrorReturn} method changes this + * behavior. If you pass a function ({@code resumeFunction}) to an {@code ObservableSource}'s {@code onErrorReturn} + * method, if the original {@code ObservableSource} encounters an error, instead of invoking its {@code Observer}'s * {@code onError} method, it will instead emit the return value of {@code resumeFunction}. *

* You can use this to prevent errors from propagating or to supply fallback data should errors be @@ -10322,31 +10829,31 @@ public final Observable onErrorResumeWith(@NonNull ObservableSource{@code onErrorReturn} does not operate by default on a particular {@link Scheduler}. *

* - * @param valueSupplier - * a function that returns a single value that will be emitted along with a regular onComplete in case - * the current Observable signals an onError event - * @return the original ObservableSource with appropriately modified behavior + * @param itemSupplier + * a function that returns a single value that will be emitted along with a regular {@code onComplete} in case + * the current {@code Observable} signals an {@code onError} event + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code itemSupplier} is {@code null} * @see ReactiveX operators documentation: Catch */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable onErrorReturn(@NonNull Function valueSupplier) { - Objects.requireNonNull(valueSupplier, "valueSupplier is null"); - return RxJavaPlugins.onAssembly(new ObservableOnErrorReturn<>(this, valueSupplier)); + public final Observable onErrorReturn(@NonNull Function itemSupplier) { + Objects.requireNonNull(itemSupplier, "itemSupplier is null"); + return RxJavaPlugins.onAssembly(new ObservableOnErrorReturn<>(this, itemSupplier)); } /** - * Instructs an ObservableSource to emit an item (returned by a specified function) rather than invoking - * {@link Observer#onError onError} if it encounters an error. + * Ends the flow with the given last item when the current {@code Observable} fails instead of signaling the error via {@code onError}. *

- * + * *

- * By default, when an ObservableSource encounters an error that prevents it from emitting the expected item to - * its {@link Observer}, the ObservableSource invokes its Observer's {@code onError} method, and then quits - * without invoking any more of its Observer's methods. The {@code onErrorReturn} method changes this - * behavior. If you pass a function ({@code resumeFunction}) to an ObservableSource's {@code onErrorReturn} - * method, if the original ObservableSource encounters an error, instead of invoking its Observer's + * By default, when an {@link ObservableSource} encounters an error that prevents it from emitting the expected item to + * its {@link Observer}, the {@code ObservableSource} invokes its {@code Observer}'s {@code onError} method, and then quits + * without invoking any more of its {@code Observer}'s methods. The {@code onErrorReturn} method changes this + * behavior. If you pass a function ({@code resumeFunction}) to an {@code ObservableSource}'s {@code onErrorReturn} + * method, if the original {@code ObservableSource} encounters an error, instead of invoking its {@code Observer}'s * {@code onError} method, it will instead emit the return value of {@code resumeFunction}. *

* You can use this to prevent errors from propagating or to supply fallback data should errors be @@ -10357,9 +10864,10 @@ public final Observable onErrorReturn(@NonNull Function * * @param item - * the value that is emitted along with a regular onComplete in case the current - * Observable signals an exception - * @return the original ObservableSource with appropriately modified behavior + * the value that is emitted along with a regular {@code onComplete} in case the current + * {@code Observable} signals an exception + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code item} is {@code null} * @see ReactiveX operators documentation: Catch */ @CheckReturnValue @@ -10371,16 +10879,16 @@ public final Observable onErrorReturnItem(@NonNull T item) { } /** - * Nulls out references to the upstream producer and downstream Observer if - * the sequence is terminated or downstream calls dispose(). + * Nulls out references to the upstream producer and downstream {@link Observer} if + * the sequence is terminated or downstream calls {@code dispose()}. *

- * + * *

*
Scheduler:
*
{@code onTerminateDetach} does not operate by default on a particular {@link Scheduler}.
*
- * @return an Observable which nulls out references to the upstream producer and downstream Observer if - * the sequence is terminated or downstream calls dispose() + * @return the new {@code Observable} instance + * the sequence is terminated or downstream calls {@code dispose()} * @since 2.0 */ @CheckReturnValue @@ -10391,18 +10899,17 @@ public final Observable onTerminateDetach() { } /** - * Returns a {@link ConnectableObservable}, which is a variety of ObservableSource that waits until its + * Returns a {@link ConnectableObservable}, which is a variety of {@link ObservableSource} that waits until its * {@link ConnectableObservable#connect connect} method is called before it begins emitting items to those * {@link Observer}s that have subscribed to it. *

- * + * *

*
Scheduler:
*
{@code publish} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@link ConnectableObservable} that upon connection causes the source ObservableSource to emit items - * to its {@link Observer}s + * @return the new {@code ConnectableObservable} instance * @see ReactiveX operators documentation: Publish */ @CheckReturnValue @@ -10413,8 +10920,8 @@ public final ConnectableObservable publish() { } /** - * Returns an Observable that emits the results of invoking a specified selector on items emitted by a - * {@link ConnectableObservable} that shares a single subscription to the underlying sequence. + * Returns an {@code Observable} that emits the results of invoking a specified selector on items emitted by a + * {@link ConnectableObservable} that shares a single subscription to the current {@code Observable} sequence. *

* *

@@ -10423,29 +10930,30 @@ public final ConnectableObservable publish() { *
* * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param selector * a function that can use the multicasted source sequence as many times as needed, without - * causing multiple subscriptions to the source sequence. Observers to the given source will + * causing multiple subscriptions to the source sequence. {@link Observer}s to the given source will * receive all notifications of the source from the time of the subscription forward. - * @return an Observable that emits the results of invoking the selector on the items emitted by a {@link ConnectableObservable} that shares a single subscription to the underlying sequence + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code selector} is {@code null} * @see ReactiveX operators documentation: Publish */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable publish(@NonNull Function, ? extends ObservableSource> selector) { + public final <@NonNull R> Observable publish(@NonNull Function, ? extends ObservableSource> selector) { Objects.requireNonNull(selector, "selector is null"); return RxJavaPlugins.onAssembly(new ObservablePublishSelector<>(this, selector)); } /** - * Returns a Maybe that applies a specified accumulator function to the first item emitted by a source - * ObservableSource, then feeds the result of that function along with the second item emitted by the source - * ObservableSource into the same function, and so on until all items have been emitted by the finite source ObservableSource, + * Returns a {@link Maybe} that applies a specified accumulator function to the first item emitted by the current + * {@code Observable}, then feeds the result of that function along with the second item emitted by the current + * {@code Observable} into the same function, and so on until all items have been emitted by the current and finite {@code Observable}, * and emits the final result from the final call to your function as its sole item. *

- * + * *

* This technique, which is called "reduce" here, is sometimes called "aggregate," "fold," "accumulate," * "compress," or "inject" in other programming contexts. Groovy, for instance, has an {@code inject} method @@ -10453,17 +10961,17 @@ public final Observable publish(@NonNull Function, *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulator object to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code reduce} does not operate by default on a particular {@link Scheduler}.
*
* * @param reducer - * an accumulator function to be invoked on each item emitted by the source ObservableSource, whose + * an accumulator function to be invoked on each item emitted by the current {@code Observable}, whose * result will be used in the next accumulator call - * @return a Maybe that emits a single item that is the result of accumulating the items emitted by - * the source ObservableSource + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code reducer} is {@code null} * @see ReactiveX operators documentation: Reduce * @see Wikipedia: Fold (higher-order function) */ @@ -10476,18 +10984,18 @@ public final Maybe reduce(@NonNull BiFunction reducer) { } /** - * Returns a Single that applies a specified accumulator function to the first item emitted by a source - * ObservableSource and a specified seed value, then feeds the result of that function along with the second item - * emitted by an ObservableSource into the same function, and so on until all items have been emitted by the - * finite source ObservableSource, emitting the final result from the final call to your function as its sole item. + * Returns a {@link Single} that applies a specified accumulator function to the first item emitted by the current + * {@code Observable} and a specified seed value, then feeds the result of that function along with the second item + * emitted by the current {@code Observable} into the same function, and so on until all items have been emitted by the + * current and finite {@code Observable}, emitting the final result from the final call to your function as its sole item. *

- * + * *

* This technique, which is called "reduce" here, is sometimes called "aggregate," "fold," "accumulate," * "compress," or "inject" in other programming contexts. Groovy, for instance, has an {@code inject} method * that does a similar operation on lists. *

- * Note that the {@code seed} is shared among all subscribers to the resulting ObservableSource + * Note that the {@code seed} is shared among all subscribers to the resulting {@code Observable} * and may cause problems if it is mutable. To make sure each subscriber gets its own value, defer * the application of this operator via {@link #defer(Supplier)}: *


@@ -10507,7 +11015,7 @@ public final Maybe reduce(@NonNull BiFunction reducer) {
      * 

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulator object to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code reduce} does not operate by default on a particular {@link Scheduler}.
@@ -10517,10 +11025,10 @@ public final Maybe reduce(@NonNull BiFunction reducer) { * @param seed * the initial (seed) accumulator value * @param reducer - * an accumulator function to be invoked on each item emitted by the source ObservableSource, the + * an accumulator function to be invoked on each item emitted by the current {@code Observable}, the * result of which will be used in the next accumulator call - * @return a Single that emits a single item that is the result of accumulating the output from the - * items emitted by the source ObservableSource + * @return the new {@code Single} instance + * @throws NullPointerException if {@code seed} or {@code reducer} is {@code null} * @see ReactiveX operators documentation: Reduce * @see Wikipedia: Fold (higher-order function) * @see #reduceWith(Supplier, BiFunction) @@ -10535,13 +11043,13 @@ public final Maybe reduce(@NonNull BiFunction reducer) { } /** - * Returns a Single that applies a specified accumulator function to the first item emitted by a source - * ObservableSource and a seed value derived from calling a specified seedSupplier, then feeds the result - * of that function along with the second item emitted by an ObservableSource into the same function, - * and so on until all items have been emitted by the finite source ObservableSource, emitting the final result + * Returns a {@link Single} that applies a specified accumulator function to the first item emitted by the current + * {@code Observable} and a seed value derived from calling a specified {@code seedSupplier}, then feeds the result + * of that function along with the second item emitted by the current {@code Observable} into the same function, + * and so on until all items have been emitted by the current and finite {@code Observable}, emitting the final result * from the final call to your function as its sole item. *

- * + * *

* This technique, which is called "reduce" here, is sometimes called "aggregate," "fold," "accumulate," * "compress," or "inject" in other programming contexts. Groovy, for instance, has an {@code inject} method @@ -10549,7 +11057,7 @@ public final Maybe reduce(@NonNull BiFunction reducer) { *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulator object to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code reduceWith} does not operate by default on a particular {@link Scheduler}.
@@ -10557,12 +11065,12 @@ public final Maybe reduce(@NonNull BiFunction reducer) { * * @param the accumulator and output value type * @param seedSupplier - * the Supplier that provides the initial (seed) accumulator value for each individual Observer + * the {@link Supplier} that provides the initial (seed) accumulator value for each individual {@link Observer} * @param reducer - * an accumulator function to be invoked on each item emitted by the source ObservableSource, the + * an accumulator function to be invoked on each item emitted by the current {@code Observable}, the * result of which will be used in the next accumulator call - * @return a Single that emits a single item that is the result of accumulating the output from the - * items emitted by the source ObservableSource + * @return the new {@code Single} instance + * @throws NullPointerException if {@code seedSupplier} or {@code reducer} is {@code null} * @see ReactiveX operators documentation: Reduce * @see Wikipedia: Fold (higher-order function) */ @@ -10576,7 +11084,7 @@ public final Maybe reduce(@NonNull BiFunction reducer) { } /** - * Returns an Observable that repeats the sequence of items emitted by the source ObservableSource indefinitely. + * Returns an {@code Observable} that repeats the sequence of items emitted by the current {@code Observable} indefinitely. *

* *

@@ -10584,7 +11092,7 @@ public final Maybe reduce(@NonNull BiFunction reducer) { *
{@code repeat} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an Observable that emits the items emitted by the source ObservableSource repeatedly and in sequence + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Repeat */ @CheckReturnValue @@ -10595,7 +11103,7 @@ public final Observable repeat() { } /** - * Returns an Observable that repeats the sequence of items emitted by the source ObservableSource at most + * Returns an {@code Observable} that repeats the sequence of items emitted by the current {@code Observable} at most * {@code count} times. *

* @@ -10605,12 +11113,11 @@ public final Observable repeat() { *

* * @param times - * the number of times the source ObservableSource items are repeated, a count of 0 will yield an empty + * the number of times the current {@code Observable} items are repeated, a count of 0 will yield an empty * sequence - * @return an Observable that repeats the sequence of items emitted by the source ObservableSource at most - * {@code count} times + * @return the new {@code Observable} instance * @throws IllegalArgumentException - * if {@code count} is less than zero + * if {@code times} is negative * @see ReactiveX operators documentation: Repeat */ @CheckReturnValue @@ -10627,22 +11134,22 @@ public final Observable repeat(long times) { } /** - * Returns an Observable that repeats the sequence of items emitted by the source ObservableSource until - * the provided stop function returns true. + * Returns an {@code Observable} that repeats the sequence of items emitted by the current {@code Observable} until + * the provided stop function returns {@code true}. *

- * + * *

*
Scheduler:
*
{@code repeatUntil} does not operate by default on a particular {@link Scheduler}.
*
* * @param stop - * a boolean supplier that is called when the current Observable completes; - * if it returns true, the returned Observable completes; if it returns false, - * the upstream Observable is resubscribed. - * @return the new Observable instance + * a boolean supplier that is called when the current {@code Observable} completes; + * if it returns {@code true}, the returned {@code Observable} completes; if it returns {@code false}, + * the current {@code Observable} is resubscribed. + * @return the new {@code Observable} instance * @throws NullPointerException - * if {@code stop} is null + * if {@code stop} is {@code null} * @see ReactiveX operators documentation: Repeat */ @CheckReturnValue @@ -10654,22 +11161,23 @@ public final Observable repeatUntil(@NonNull BooleanSupplier stop) { } /** - * Returns an Observable that emits the same values as the source ObservableSource with the exception of an + * Returns an {@code Observable} that emits the same values as the current {@code Observable} with the exception of an * {@code onComplete}. An {@code onComplete} notification from the source will result in the emission of - * a {@code void} item to the ObservableSource provided as an argument to the {@code notificationHandler} - * function. If that ObservableSource calls {@code onComplete} or {@code onError} then {@code repeatWhen} will - * call {@code onComplete} or {@code onError} on the child subscription. Otherwise, this ObservableSource will - * resubscribe to the source ObservableSource. + * a {@code void} item to the {@link ObservableSource} provided as an argument to the {@code notificationHandler} + * function. If that {@code ObservableSource} calls {@code onComplete} or {@code onError} then {@code repeatWhen} will + * call {@code onComplete} or {@code onError} on the child subscription. Otherwise, the current {@code Observable} + * will be resubscribed. *

- * + * *

*
Scheduler:
*
{@code repeatWhen} does not operate by default on a particular {@link Scheduler}.
*
* * @param handler - * receives an ObservableSource of notifications with which a user can complete or error, aborting the repeat. - * @return the source ObservableSource modified with repeat logic + * receives an {@code ObservableSource} of notifications with which a user can complete or error, aborting the repeat. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code handler} is {@code null} * @see ReactiveX operators documentation: Repeat */ @CheckReturnValue @@ -10681,19 +11189,18 @@ public final Observable repeatWhen(@NonNull Function - * + * *
*
Scheduler:
*
This version of {@code replay} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@link ConnectableObservable} that upon connection causes the source ObservableSource to emit its - * items to its {@link Observer}s + * @return the new {@code ConnectableObservable} instance * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @@ -10704,8 +11211,8 @@ public final ConnectableObservable replay() { } /** - * Returns an Observable that emits items that are the results of invoking a specified selector on the items - * emitted by a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource. + * Returns an {@code Observable} that emits items that are the results of invoking a specified selector on the items + * emitted by a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable}. *

* *

@@ -10714,99 +11221,99 @@ public final ConnectableObservable replay() { *
* * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param selector * the selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the ObservableSource - * @return an Observable that emits items that are the results of invoking the selector on a - * {@link ConnectableObservable} that shares a single subscription to the source ObservableSource + * causing multiple subscriptions to the current {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code selector} is {@code null} * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable replay(@NonNull Function, ? extends ObservableSource> selector) { + public final <@NonNull R> Observable replay(@NonNull Function, ? extends ObservableSource> selector) { Objects.requireNonNull(selector, "selector is null"); return ObservableReplay.multicastSelector(ObservableInternalHelper.replaySupplier(this), selector); } /** - * Returns an Observable that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, + * Returns an {@code Observable} that emits items that are the results of invoking a specified selector on items + * emitted by a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable}, * replaying {@code bufferSize} notifications. *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. *

- * + * *

*
Scheduler:
*
This version of {@code replay} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param selector * the selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the ObservableSource + * causing multiple subscriptions to the current {@code Observable} * @param bufferSize - * the buffer size that limits the number of items the connectable ObservableSource can replay - * @return an Observable that emits items that are the results of invoking the selector on items emitted by - * a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource - * replaying no more than {@code bufferSize} items + * the buffer size that limits the number of items the connectable {@code Observable} can replay + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code selector} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay * @see #replay(Function, int, boolean) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable replay(@NonNull Function, ? extends ObservableSource> selector, int bufferSize) { + public final <@NonNull R> Observable replay(@NonNull Function, ? extends ObservableSource> selector, int bufferSize) { Objects.requireNonNull(selector, "selector is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); return ObservableReplay.multicastSelector(ObservableInternalHelper.replaySupplier(this, bufferSize, false), selector); } /** - * Returns an Observable that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, + * Returns an {@code Observable} that emits items that are the results of invoking a specified selector on items + * emitted by a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable}, * replaying {@code bufferSize} notifications. *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. *

- * + * *

*
Scheduler:
*
This version of {@code replay} does not operate by default on a particular {@link Scheduler}.
*
* * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param selector * the selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the ObservableSource + * causing multiple subscriptions to the current {@code Observable} * @param bufferSize - * the buffer size that limits the number of items the connectable ObservableSource can replay + * the buffer size that limits the number of items the connectable {@code Observable} can replay * @param eagerTruncate - * if true, whenever the internal buffer is truncated to the given bufferSize, the + * if {@code true}, whenever the internal buffer is truncated to the given bufferSize, the * oldest item will be guaranteed dereferenced, thus avoiding unexpected retention - * @return an Observable that emits items that are the results of invoking the selector on items emitted by - * a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource - * replaying no more than {@code bufferSize} items + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code selector} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable replay(@NonNull Function, ? extends ObservableSource> selector, int bufferSize, boolean eagerTruncate) { + public final <@NonNull R> Observable replay(@NonNull Function, ? extends ObservableSource> selector, int bufferSize, boolean eagerTruncate) { Objects.requireNonNull(selector, "selector is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); return ObservableReplay.multicastSelector(ObservableInternalHelper.replaySupplier(this, bufferSize, eagerTruncate), selector); } /** - * Returns an Observable that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, + * Returns an {@code Observable} that emits items that are the results of invoking a specified selector on items + * emitted by a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable}, * replaying no more than {@code bufferSize} items that were emitted within a specified time window. *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than @@ -10819,69 +11326,67 @@ public final Observable replay(@NonNull Function, ? *

* * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param selector * a selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the ObservableSource + * causing multiple subscriptions to the current {@code Observable} * @param bufferSize - * the buffer size that limits the number of items the connectable ObservableSource can replay + * the buffer size that limits the number of items the connectable {@code Observable} can replay * @param time * the duration of the window in which the replayed items must have been emitted * @param unit * the time unit of {@code time} - * @return an Observable that emits items that are the results of invoking the selector on items emitted by - * a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, and - * replays no more than {@code bufferSize} items that were emitted within the window defined by - * {@code time} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code selector} or {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Observable replay(@NonNull Function, ? extends ObservableSource> selector, int bufferSize, long time, @NonNull TimeUnit unit) { + public final <@NonNull R> Observable replay(@NonNull Function, ? extends ObservableSource> selector, int bufferSize, long time, @NonNull TimeUnit unit) { return replay(selector, bufferSize, time, unit, Schedulers.computation()); } /** - * Returns an Observable that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, + * Returns an {@code Observable} that emits items that are the results of invoking a specified selector on items + * emitted by a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable}, * replaying no more than {@code bufferSize} items that were emitted within a specified time window. *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. *

- * + * *

*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
* * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param selector * a selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the ObservableSource + * causing multiple subscriptions to the current {@code Observable} * @param bufferSize - * the buffer size that limits the number of items the connectable ObservableSource can replay + * the buffer size that limits the number of items the connectable {@code Observable} can replay * @param time * the duration of the window in which the replayed items must have been emitted * @param unit * the time unit of {@code time} * @param scheduler - * the Scheduler that is the time source for the window - * @return an Observable that emits items that are the results of invoking the selector on items emitted by - * a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, and - * replays no more than {@code bufferSize} items that were emitted within the window defined by - * {@code time} + * the {@code Scheduler} that is the time source for the window + * @return the new {@code Observable} instance * @throws IllegalArgumentException - * if {@code bufferSize} is less than zero + * if {@code bufferSize} is non-positive + * @throws NullPointerException if {@code selector}, {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay * @see #replay(Function, int, long, TimeUnit, Scheduler, boolean) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable replay(@NonNull Function, ? extends ObservableSource> selector, int bufferSize, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + public final <@NonNull R> Observable replay(@NonNull Function, ? extends ObservableSource> selector, int bufferSize, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { Objects.requireNonNull(selector, "selector is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); Objects.requireNonNull(unit, "unit is null"); @@ -10889,48 +11394,47 @@ public final Observable replay(@NonNull Function, ? return ObservableReplay.multicastSelector( ObservableInternalHelper.replaySupplier(this, bufferSize, time, unit, scheduler, false), selector); } + /** - * Returns an Observable that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, + * Returns an {@code Observable} that emits items that are the results of invoking a specified selector on items + * emitted by a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable}, * replaying no more than {@code bufferSize} items that were emitted within a specified time window. *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. *

- * + * *

*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
* * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param selector * a selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the ObservableSource + * causing multiple subscriptions to the current {@code Observable} * @param bufferSize - * the buffer size that limits the number of items the connectable ObservableSource can replay + * the buffer size that limits the number of items the connectable {@code Observable} can replay * @param time * the duration of the window in which the replayed items must have been emitted * @param unit * the time unit of {@code time} * @param scheduler - * the Scheduler that is the time source for the window + * the {@code Scheduler} that is the time source for the window * @param eagerTruncate - * if true, whenever the internal buffer is truncated to the given bufferSize/age, the + * if {@code true}, whenever the internal buffer is truncated to the given bufferSize/age, the * oldest item will be guaranteed dereferenced, thus avoiding unexpected retention - * @return an Observable that emits items that are the results of invoking the selector on items emitted by - * a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, and - * replays no more than {@code bufferSize} items that were emitted within the window defined by - * {@code time} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code selector}, {@code unit} or {@code scheduler} is {@code null} * @throws IllegalArgumentException - * if {@code bufferSize} is less than zero + * if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable replay(@NonNull Function, ? extends ObservableSource> selector, int bufferSize, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean eagerTruncate) { + public final <@NonNull R> Observable replay(@NonNull Function, ? extends ObservableSource> selector, int bufferSize, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean eagerTruncate) { Objects.requireNonNull(selector, "selector is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); Objects.requireNonNull(unit, "unit is null"); @@ -10940,69 +11444,67 @@ public final Observable replay(@NonNull Function, ? } /** - * Returns an Observable that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, + * Returns an {@code Observable} that emits items that are the results of invoking a specified selector on items + * emitted by a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable}, * replaying all items that were emitted within a specified time window. *

- * + * *

*
Scheduler:
*
This version of {@code replay} operates by default on the {@code computation} {@link Scheduler}.
*
* * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param selector * a selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the ObservableSource + * causing multiple subscriptions to the current {@code Observable} * @param time * the duration of the window in which the replayed items must have been emitted * @param unit * the time unit of {@code time} - * @return an Observable that emits items that are the results of invoking the selector on items emitted by - * a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, - * replaying all items that were emitted within the window defined by {@code time} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code selector} or {@code unit} is {@code null} * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Observable replay(@NonNull Function, ? extends ObservableSource> selector, long time, @NonNull TimeUnit unit) { + public final <@NonNull R> Observable replay(@NonNull Function, ? extends ObservableSource> selector, long time, @NonNull TimeUnit unit) { return replay(selector, time, unit, Schedulers.computation()); } /** - * Returns an Observable that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, + * Returns an {@code Observable} that emits items that are the results of invoking a specified selector on items + * emitted by a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable}, * replaying all items that were emitted within a specified time window. *

- * + * *

*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
* * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param selector * a selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the ObservableSource + * causing multiple subscriptions to the current {@code Observable} * @param time * the duration of the window in which the replayed items must have been emitted * @param unit * the time unit of {@code time} * @param scheduler * the scheduler that is the time source for the window - * @return an Observable that emits items that are the results of invoking the selector on items emitted by - * a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, - * replaying all items that were emitted within the window defined by {@code time} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code selector}, {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Replay * @see #replay(Function, long, TimeUnit, Scheduler, boolean) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable replay(@NonNull Function, ? extends ObservableSource> selector, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + public final <@NonNull R> Observable replay(@NonNull Function, ? extends ObservableSource> selector, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { Objects.requireNonNull(selector, "selector is null"); Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); @@ -11010,21 +11512,21 @@ public final Observable replay(@NonNull Function, ? } /** - * Returns an Observable that emits items that are the results of invoking a specified selector on items - * emitted by a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, + * Returns an {@code Observable} that emits items that are the results of invoking a specified selector on items + * emitted by a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable}, * replaying all items that were emitted within a specified time window. *

- * + * *

*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
*
* * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param selector * a selector function, which can use the multicasted sequence as many times as needed, without - * causing multiple subscriptions to the ObservableSource + * causing multiple subscriptions to the current {@code Observable} * @param time * the duration of the window in which the replayed items must have been emitted * @param unit @@ -11032,17 +11534,16 @@ public final Observable replay(@NonNull Function, ? * @param scheduler * the scheduler that is the time source for the window * @param eagerTruncate - * if true, whenever the internal buffer is truncated to the given age, the + * if {@code true}, whenever the internal buffer is truncated to the given age, the * oldest item will be guaranteed dereferenced, thus avoiding unexpected retention - * @return an Observable that emits items that are the results of invoking the selector on items emitted by - * a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource, - * replaying all items that were emitted within the window defined by {@code time} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code selector}, {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable replay(@NonNull Function, ? extends ObservableSource> selector, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean eagerTruncate) { + public final <@NonNull R> Observable replay(@NonNull Function, ? extends ObservableSource> selector, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean eagerTruncate) { Objects.requireNonNull(selector, "selector is null"); Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); @@ -11050,12 +11551,12 @@ public final Observable replay(@NonNull Function, ? } /** - * Returns a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource that - * replays at most {@code bufferSize} items emitted by that ObservableSource. A Connectable ObservableSource resembles - * an ordinary ObservableSource, except that it does not begin emitting items when it is subscribed to, but only + * Returns a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable} that + * replays at most {@code bufferSize} items emitted by the current {@code Observable}. A connectable {@code Observable} resembles + * an ordinary {@code Observable}, except that it does not begin emitting items when it is subscribed to, but only * when its {@code connect} method is called. *

- * + * *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. @@ -11068,8 +11569,8 @@ public final Observable replay(@NonNull Function, ? * * @param bufferSize * the buffer size that limits the number of items that can be replayed - * @return a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and - * replays at most {@code bufferSize} items emitted by that ObservableSource + * @return the new {@code ConnectableObservable} instance + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay * @see #replay(int, boolean) */ @@ -11082,12 +11583,12 @@ public final ConnectableObservable replay(int bufferSize) { } /** - * Returns a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource that - * replays at most {@code bufferSize} items emitted by that ObservableSource. A Connectable ObservableSource resembles - * an ordinary ObservableSource, except that it does not begin emitting items when it is subscribed to, but only + * Returns a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable} that + * replays at most {@code bufferSize} items emitted by the current {@code Observable}. A connectable {@code Observable} resembles + * an ordinary {@code Observable}, except that it does not begin emitting items when it is subscribed to, but only * when its {@code connect} method is called. *

- * + * *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. @@ -11100,10 +11601,10 @@ public final ConnectableObservable replay(int bufferSize) { * @param bufferSize * the buffer size that limits the number of items that can be replayed * @param eagerTruncate - * if true, whenever the internal buffer is truncated to the given bufferSize/age, the + * if {@code true}, whenever the internal buffer is truncated to the given bufferSize/age, the * oldest item will be guaranteed dereferenced, thus avoiding unexpected retention - * @return a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and - * replays at most {@code bufferSize} items emitted by that ObservableSource + * @return the new {@code ConnectableObservable} instance + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @@ -11115,12 +11616,12 @@ public final ConnectableObservable replay(int bufferSize, boolean eagerTrunca } /** - * Returns a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and - * replays at most {@code bufferSize} items that were emitted during a specified time window. A Connectable - * ObservableSource resembles an ordinary ObservableSource, except that it does not begin emitting items when it is + * Returns a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable} and + * replays at most {@code bufferSize} items that were emitted during a specified time window. A connectable + * {@code Observable} resembles an ordinary {@code Observable}, except that it does not begin emitting items when it is * subscribed to, but only when its {@code connect} method is called. *

- * + * *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. @@ -11137,9 +11638,9 @@ public final ConnectableObservable replay(int bufferSize, boolean eagerTrunca * the duration of the window in which the replayed items must have been emitted * @param unit * the time unit of {@code time} - * @return a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and - * replays at most {@code bufferSize} items that were emitted during the window defined by - * {@code time} + * @return the new {@code ConnectableObservable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay * @see #replay(int, long, TimeUnit, Scheduler, boolean) */ @@ -11151,9 +11652,9 @@ public final ConnectableObservable replay(int bufferSize, long time, @NonNull } /** - * Returns a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and + * Returns a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable} and * that replays a maximum of {@code bufferSize} items that are emitted within a specified time window. A - * Connectable ObservableSource resembles an ordinary ObservableSource, except that it does not begin emitting items + * connectable {@code Observable} resembles an ordinary {@code Observable}, except that it does not begin emitting items * when it is subscribed to, but only when its {@code connect} method is called. *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than @@ -11161,7 +11662,7 @@ public final ConnectableObservable replay(int bufferSize, long time, @NonNull * To ensure no out-of-date or beyond-bufferSize items are referenced, * use the {@link #replay(int, long, TimeUnit, Scheduler, boolean)} overload with {@code eagerTruncate = true}. *

- * + * *

*
Scheduler:
*
You specify which {@link Scheduler} this operator will use.
@@ -11175,11 +11676,10 @@ public final ConnectableObservable replay(int bufferSize, long time, @NonNull * the time unit of {@code time} * @param scheduler * the scheduler that is used as a time source for the window - * @return a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and - * replays at most {@code bufferSize} items that were emitted during the window defined by - * {@code time} + * @return the new {@code ConnectableObservable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @throws IllegalArgumentException - * if {@code bufferSize} is less than zero + * if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay * @see #replay(int, long, TimeUnit, Scheduler, boolean) */ @@ -11194,12 +11694,12 @@ public final ConnectableObservable replay(int bufferSize, long time, @NonNull } /** - * Returns a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and + * Returns a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable} and * that replays a maximum of {@code bufferSize} items that are emitted within a specified time window. A - * Connectable ObservableSource resembles an ordinary ObservableSource, except that it does not begin emitting items + * connectable {@code Observable} resembles an ordinary {@code Observable}, except that it does not begin emitting items * when it is subscribed to, but only when its {@code connect} method is called. *

- * + * *

* Note that due to concurrency requirements, {@code replay(bufferSize)} may hold strong references to more than * {@code bufferSize} source emissions. @@ -11218,14 +11718,13 @@ public final ConnectableObservable replay(int bufferSize, long time, @NonNull * the time unit of {@code time} * @param scheduler * the scheduler that is used as a time source for the window - * @return a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and - * replays at most {@code bufferSize} items that were emitted during the window defined by - * {@code time} + * @return the new {@code ConnectableObservable} instance * @param eagerTruncate - * if true, whenever the internal buffer is truncated to the given bufferSize/age, the + * if {@code true}, whenever the internal buffer is truncated to the given bufferSize/age, the * oldest item will be guaranteed dereferenced, thus avoiding unexpected retention + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @throws IllegalArgumentException - * if {@code bufferSize} is less than zero + * if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @@ -11239,12 +11738,12 @@ public final ConnectableObservable replay(int bufferSize, long time, @NonNull } /** - * Returns a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and - * replays all items emitted by that ObservableSource within a specified time window. A Connectable ObservableSource - * resembles an ordinary ObservableSource, except that it does not begin emitting items when it is subscribed to, + * Returns a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable} and + * replays all items emitted by the current {@code Observable} within a specified time window. A connectable {@code Observable} + * resembles an ordinary {@code Observable}, except that it does not begin emitting items when it is subscribed to, * but only when its {@code connect} method is called. *

- * + * *

*
Scheduler:
*
This version of {@code replay} operates by default on the {@code computation} {@link Scheduler}.
@@ -11254,8 +11753,8 @@ public final ConnectableObservable replay(int bufferSize, long time, @NonNull * the duration of the window in which the replayed items must have been emitted * @param unit * the time unit of {@code time} - * @return a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and - * replays the items that were emitted during the window defined by {@code time} + * @return the new {@code ConnectableObservable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @@ -11266,12 +11765,12 @@ public final ConnectableObservable replay(long time, @NonNull TimeUnit unit) } /** - * Returns a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and - * replays all items emitted by that ObservableSource within a specified time window. A Connectable ObservableSource - * resembles an ordinary ObservableSource, except that it does not begin emitting items when it is subscribed to, + * Returns a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable} and + * replays all items emitted by the current {@code Observable} within a specified time window. A connectable {@code Observable} + * resembles an ordinary {@code Observable}, except that it does not begin emitting items when it is subscribed to, * but only when its {@code connect} method is called. *

- * + * *

* Note that the internal buffer may retain strong references to the oldest item. To ensure no out-of-date items * are referenced, use the {@link #replay(long, TimeUnit, Scheduler, boolean)} overload with {@code eagerTruncate = true}. @@ -11285,9 +11784,9 @@ public final ConnectableObservable replay(long time, @NonNull TimeUnit unit) * @param unit * the time unit of {@code time} * @param scheduler - * the Scheduler that is the time source for the window - * @return a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and - * replays the items that were emitted during the window defined by {@code time} + * the {@code Scheduler} that is the time source for the window + * @return the new {@code ConnectableObservable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Replay * @see #replay(long, TimeUnit, Scheduler, boolean) */ @@ -11301,12 +11800,12 @@ public final ConnectableObservable replay(long time, @NonNull TimeUnit unit, } /** - * Returns a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and - * replays all items emitted by that ObservableSource within a specified time window. A Connectable ObservableSource - * resembles an ordinary ObservableSource, except that it does not begin emitting items when it is subscribed to, + * Returns a {@link ConnectableObservable} that shares a single subscription to the current {@code Observable} and + * replays all items emitted by the current {@code Observable} within a specified time window. A connectable {@code Observable} + * resembles an ordinary {@code Observable}, except that it does not begin emitting items when it is subscribed to, * but only when its {@code connect} method is called. *

- * + * *

* Note that the internal buffer may retain strong references to the oldest item. To ensure no out-of-date items * are referenced, set {@code eagerTruncate = true}. @@ -11320,12 +11819,12 @@ public final ConnectableObservable replay(long time, @NonNull TimeUnit unit, * @param unit * the time unit of {@code time} * @param scheduler - * the Scheduler that is the time source for the window + * the {@code Scheduler} that is the time source for the window * @param eagerTruncate - * if true, whenever the internal buffer is truncated to the given bufferSize/age, the + * if {@code true}, whenever the internal buffer is truncated to the given bufferSize/age, the * oldest item will be guaranteed dereferenced, thus avoiding unexpected retention - * @return a {@link ConnectableObservable} that shares a single subscription to the source ObservableSource and - * replays the items that were emitted during the window defined by {@code time} + * @return the new {@code ConnectableObservable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Replay */ @CheckReturnValue @@ -11338,16 +11837,16 @@ public final ConnectableObservable replay(long time, @NonNull TimeUnit unit, } /** - * Returns an Observable that mirrors the source ObservableSource, resubscribing to it if it calls {@code onError} + * Returns an {@code Observable} that mirrors the current {@code Observable}, resubscribing to it if it calls {@code onError} * (infinite retry count). *

- * + * *

- * If the source ObservableSource calls {@link Observer#onError}, this method will resubscribe to the source - * ObservableSource rather than propagating the {@code onError} call. + * If the current {@code Observable} calls {@link Observer#onError}, this method will resubscribe to the current + * {@code Observable} rather than propagating the {@code onError} call. *

- * Any and all items emitted by the source ObservableSource will be emitted by the resulting ObservableSource, even - * those emitted during failed subscriptions. For example, if an ObservableSource fails at first but emits + * Any and all items emitted by the current {@code Observable} will be emitted by the resulting {@code Observable}, even + * those emitted during failed subscriptions. For example, if the current {@code Observable} fails at first but emits * {@code [1, 2]} then succeeds the second time and emits {@code [1, 2, 3, 4, 5]} then the complete sequence * of emissions and notifications would be {@code [1, 2, 1, 2, 3, 4, 5, onComplete]}. *

@@ -11355,7 +11854,7 @@ public final ConnectableObservable replay(long time, @NonNull TimeUnit unit, *
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
* - * @return the source ObservableSource modified with retry logic + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Retry */ @CheckReturnValue @@ -11366,10 +11865,10 @@ public final Observable retry() { } /** - * Returns an Observable that mirrors the source ObservableSource, resubscribing to it if it calls {@code onError} - * and the predicate returns true for that specific exception and retry count. + * Returns an {@code Observable} that mirrors the current {@code Observable}, resubscribing to it if it calls {@code onError} + * and the predicate returns {@code true} for that specific exception and retry count. *

- * + * *

*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
@@ -11378,7 +11877,8 @@ public final Observable retry() { * @param predicate * the predicate that determines if a resubscription may happen in case of a specific exception * and retry count - * @return the source ObservableSource modified with retry logic + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @see #retry() * @see ReactiveX operators documentation: Retry */ @@ -11392,17 +11892,17 @@ public final Observable retry(@NonNull BiPredicate - * + * *

- * If the source ObservableSource calls {@link Observer#onError}, this method will resubscribe to the source - * ObservableSource for a maximum of {@code count} resubscriptions rather than propagating the + * If the current {@code Observable} calls {@link Observer#onError}, this method will resubscribe to the current + * {@code Observable} for a maximum of {@code count} resubscriptions rather than propagating the * {@code onError} call. *

- * Any and all items emitted by the source ObservableSource will be emitted by the resulting ObservableSource, even - * those emitted during failed subscriptions. For example, if an ObservableSource fails at first but emits + * Any and all items emitted by the current {@code Observable} will be emitted by the resulting {@code Observable}, even + * those emitted during failed subscriptions. For example, if the current {@code Observable} fails at first but emits * {@code [1, 2]} then succeeds the second time and emits {@code [1, 2, 3, 4, 5]} then the complete sequence * of emissions and notifications would be {@code [1, 2, 1, 2, 3, 4, 5, onComplete]}. *

@@ -11411,8 +11911,9 @@ public final Observable retry(@NonNull BiPredicate * * @param times - * the number of times to resubscribe if the current Observable fails - * @return the source ObservableSource modified with retry logic + * the number of times to resubscribe if the current {@code Observable} fails + * @return the new {@code Observable} instance + * @throws IllegalArgumentException if {@code times} is negative * @see ReactiveX operators documentation: Retry */ @CheckReturnValue @@ -11423,16 +11924,18 @@ public final Observable retry(long times) { } /** - * Retries at most times or until the predicate returns false, whichever happens first. + * Retries at most times or until the predicate returns {@code false}, whichever happens first. *

- * + * *

*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
- * @param times the number of times to resubscribe if the current Observable fails - * @param predicate the predicate called with the failure Throwable and should return true to trigger a retry. - * @return the new Observable instance + * @param times the number of times to resubscribe if the current {@code Observable} fails + * @param predicate the predicate called with the failure {@link Throwable} and should return {@code true} to trigger a retry. + * @throws NullPointerException if {@code predicate} is {@code null} + * @throws IllegalArgumentException if {@code times} is negative + * @return the new {@code Observable} instance */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -11447,16 +11950,17 @@ public final Observable retry(long times, @NonNull Predicate - * + * *
*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
* - * @param predicate the predicate that receives the failure Throwable and should return true to trigger a retry. - * @return the new Observable instance + * @param predicate the predicate that receives the failure {@link Throwable} and should return {@code true} to trigger a retry. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code predicate} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -11466,15 +11970,16 @@ public final Observable retry(@NonNull Predicate predicate } /** - * Retries until the given stop function returns true. + * Retries until the given stop function returns {@code true}. *

- * + * *

*
Scheduler:
*
{@code retryUntil} does not operate by default on a particular {@link Scheduler}.
*
- * @param stop the function that should return true to stop retrying - * @return the new Observable instance + * @param stop the function that should return {@code true} to stop retrying + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code stop} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -11485,14 +11990,14 @@ public final Observable retryUntil(@NonNull BooleanSupplier stop) { } /** - * Returns an Observable that emits the same values as the source ObservableSource with the exception of an + * Returns an {@code Observable} that emits the same values as the current {@code Observable} with the exception of an * {@code onError}. An {@code onError} notification from the source will result in the emission of a - * {@link Throwable} item to the ObservableSource provided as an argument to the {@code notificationHandler} - * function. If that ObservableSource calls {@code onComplete} or {@code onError} then {@code retry} will call - * {@code onComplete} or {@code onError} on the child subscription. Otherwise, this ObservableSource will - * resubscribe to the source ObservableSource. + * {@link Throwable} item to the {@code Observable} provided as an argument to the {@code notificationHandler} + * function. If that {@code Observable} calls {@code onComplete} or {@code onError} then {@code retry} will call + * {@code onComplete} or {@code onError} on the child subscription. Otherwise, the current {@code Observable} + * will be resubscribed. *

- * + * *

* Example: * @@ -11522,10 +12027,10 @@ public final Observable retryUntil(@NonNull BooleanSupplier stop) { * subscribing * }

*

- * Note that the inner {@code ObservableSource} returned by the handler function should signal + * Note that the inner {@link ObservableSource} returned by the handler function should signal * either {@code onNext}, {@code onError} or {@code onComplete} in response to the received * {@code Throwable} to indicate the operator should retry or terminate. If the upstream to - * the operator is asynchronous, signalling onNext followed by onComplete immediately may + * the operator is asynchronous, signaling {@code onNext} followed by {@code onComplete} immediately may * result in the sequence to be completed immediately. Similarly, if this inner * {@code ObservableSource} signals {@code onError} or {@code onComplete} while the upstream is * active, the sequence is terminated with the same signal immediately. @@ -11552,9 +12057,10 @@ public final Observable retryUntil(@NonNull BooleanSupplier stop) { *

* * @param handler - * receives an ObservableSource of notifications with which a user can complete or error, aborting the + * receives an {@code Observable} of notifications with which a user can complete or error, aborting the * retry - * @return the source ObservableSource modified with retry logic + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code handler} is {@code null} * @see ReactiveX operators documentation: Retry */ @CheckReturnValue @@ -11567,19 +12073,18 @@ public final Observable retryWhen( } /** - * Subscribes to the current Observable and wraps the given Observer into a SafeObserver - * (if not already a SafeObserver) that - * deals with exceptions thrown by a misbehaving Observer (that doesn't follow the - * Reactive-Streams specification). + * Subscribes to the current {@code Observable} and wraps the given {@link Observer} into a {@link SafeObserver} + * (if not already a {@code SafeObserver}) that + * deals with exceptions thrown by a misbehaving {@code Observer} (that doesn't follow the + * Reactive Streams specification). *
*
Scheduler:
*
{@code safeSubscribe} does not operate by default on a particular {@link Scheduler}.
*
- * @param observer the incoming Observer instance - * @throws NullPointerException if s is null + * @param observer the incoming {@code Observer} instance + * @throws NullPointerException if {@code observer} is {@code null} */ @SchedulerSupport(SchedulerSupport.NONE) - @NonNull public final void safeSubscribe(@NonNull Observer observer) { Objects.requireNonNull(observer, "observer is null"); if (observer instanceof SafeObserver) { @@ -11590,10 +12095,10 @@ public final void safeSubscribe(@NonNull Observer observer) { } /** - * Returns an Observable that emits the most recently emitted item (if any) emitted by the source ObservableSource + * Returns an {@code Observable} that emits the most recently emitted item (if any) emitted by the current {@code Observable} * within periodic time intervals. *

- * + * *

*
Scheduler:
*
{@code sample} operates by default on the {@code computation} {@link Scheduler}.
@@ -11603,8 +12108,8 @@ public final void safeSubscribe(@NonNull Observer observer) { * the sampling rate * @param unit * the {@link TimeUnit} in which {@code period} is defined - * @return an Observable that emits the results of sampling the items emitted by the source ObservableSource at - * the specified time interval + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Sample * @see #throttleLast(long, TimeUnit) */ @@ -11616,10 +12121,10 @@ public final Observable sample(long period, @NonNull TimeUnit unit) { } /** - * Returns an Observable that emits the most recently emitted item (if any) emitted by the source ObservableSource + * Returns an {@code Observable} that emits the most recently emitted item (if any) emitted by the current {@code Observable} * within periodic time intervals and optionally emit the very last upstream item when the upstream completes. *

- * + * *

*
Scheduler:
*
{@code sample} operates by default on the {@code computation} {@link Scheduler}.
@@ -11630,12 +12135,12 @@ public final Observable sample(long period, @NonNull TimeUnit unit) { * the sampling rate * @param unit * the {@link TimeUnit} in which {@code period} is defined - * @return an Observable that emits the results of sampling the items emitted by the source ObservableSource at - * the specified time interval * @param emitLast - * if true and the upstream completes while there is still an unsampled item available, + * if {@code true} and the upstream completes while there is still an unsampled item available, * that item is emitted to downstream before completion - * if false, an unsampled last item is ignored. + * if {@code false}, an unsampled last item is ignored. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Sample * @see #throttleLast(long, TimeUnit) * @since 2.1 @@ -11648,13 +12153,13 @@ public final Observable sample(long period, @NonNull TimeUnit unit, boolean e } /** - * Returns an Observable that emits the most recently emitted item (if any) emitted by the source ObservableSource - * within periodic time intervals, where the intervals are defined on a particular Scheduler. + * Returns an {@code Observable} that emits the most recently emitted item (if any) emitted by the current {@code Observable} + * within periodic time intervals, where the intervals are defined on a particular {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param period @@ -11662,9 +12167,9 @@ public final Observable sample(long period, @NonNull TimeUnit unit, boolean e * @param unit * the {@link TimeUnit} in which {@code period} is defined * @param scheduler - * the {@link Scheduler} to use when sampling - * @return an Observable that emits the results of sampling the items emitted by the source ObservableSource at - * the specified time interval + * the {@code Scheduler} to use when sampling + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Sample * @see #throttleLast(long, TimeUnit, Scheduler) */ @@ -11674,18 +12179,18 @@ public final Observable sample(long period, @NonNull TimeUnit unit, boolean e public final Observable sample(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new ObservableSampleTimed<>(this, period, unit, scheduler, false)); + return RxJavaPlugins.onAssembly(new ObservableSampleTimed<>(this, period, unit, scheduler, false, null)); } /** - * Returns an Observable that emits the most recently emitted item (if any) emitted by the source ObservableSource - * within periodic time intervals, where the intervals are defined on a particular Scheduler + * Returns an {@code Observable} that emits the most recently emitted item (if any) emitted by the current {@code Observable} + * within periodic time intervals, where the intervals are defined on a particular {@link Scheduler} * and optionally emit the very last upstream item when the upstream completes. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* *

History: 2.0.5 - experimental @@ -11694,13 +12199,13 @@ public final Observable sample(long period, @NonNull TimeUnit unit, @NonNull * @param unit * the {@link TimeUnit} in which {@code period} is defined * @param scheduler - * the {@link Scheduler} to use when sampling + * the {@code Scheduler} to use when sampling * @param emitLast - * if true and the upstream completes while there is still an unsampled item available, + * if {@code true} and the upstream completes while there is still an unsampled item available, * that item is emitted to downstream before completion - * if false, an unsampled last item is ignored. - * @return an Observable that emits the results of sampling the items emitted by the source ObservableSource at - * the specified time interval + * if {@code false}, an unsampled last item is ignored. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Sample * @see #throttleLast(long, TimeUnit, Scheduler) * @since 2.1 @@ -11711,75 +12216,113 @@ public final Observable sample(long period, @NonNull TimeUnit unit, @NonNull public final Observable sample(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new ObservableSampleTimed<>(this, period, unit, scheduler, emitLast)); + return RxJavaPlugins.onAssembly(new ObservableSampleTimed<>(this, period, unit, scheduler, emitLast, null)); } /** - * Returns an Observable that, when the specified {@code sampler} ObservableSource emits an item or completes, - * emits the most recently emitted item (if any) emitted by the source ObservableSource since the previous - * emission from the {@code sampler} ObservableSource. + * Returns an {@code Observable} that emits the most recently emitted item (if any) emitted by the current {@code Observable} + * within periodic time intervals, where the intervals are defined on a particular {@link Scheduler}. *

- * + * + *

+ *
Scheduler:
+ *
You specify which {@code Scheduler} this operator will use.
+ *
+ * + * @param period + * the sampling rate + * @param unit + * the {@link TimeUnit} in which {@code period} is defined + * @param scheduler + * the {@code Scheduler} to use when sampling + * @param emitLast + * if {@code true} and the upstream completes while there is still an unsampled item available, + * that item is emitted to downstream before completion + * if {@code false}, an unsampled last item is ignored. + * @param onDropped + * called with the current entry when it has been replaced by a new one + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} or {@code onDropped} is {@code null} + * @see ReactiveX operators documentation: Sample + * @see #throttleLast(long, TimeUnit, Scheduler) + * @since 3.1.6 - Experimental + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.CUSTOM) + @NonNull + @Experimental + public final Observable sample(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast, @NonNull Consumer onDropped) { + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + Objects.requireNonNull(onDropped, "onDropped is null"); + return RxJavaPlugins.onAssembly(new ObservableSampleTimed<>(this, period, unit, scheduler, emitLast, onDropped)); + } + + /** + * Returns an {@code Observable} that, when the specified {@code sampler} {@link ObservableSource} emits an item or completes, + * emits the most recently emitted item (if any) emitted by the current {@code Observable} since the previous + * emission from the {@code sampler} {@code ObservableSource}. + *

+ * *

*
Scheduler:
*
This version of {@code sample} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the element type of the sampler ObservableSource + * @param the element type of the sampler {@code ObservableSource} * @param sampler - * the ObservableSource to use for sampling the source ObservableSource - * @return an Observable that emits the results of sampling the items emitted by this ObservableSource whenever - * the {@code sampler} ObservableSource emits an item or completes + * the {@code ObservableSource} to use for sampling the current {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sampler} is {@code null} * @see ReactiveX operators documentation: Sample */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable sample(@NonNull ObservableSource sampler) { + public final <@NonNull U> Observable sample(@NonNull ObservableSource sampler) { Objects.requireNonNull(sampler, "sampler is null"); return RxJavaPlugins.onAssembly(new ObservableSampleWithObservable<>(this, sampler, false)); } /** - * Returns an Observable that, when the specified {@code sampler} ObservableSource emits an item or completes, - * emits the most recently emitted item (if any) emitted by the source ObservableSource since the previous - * emission from the {@code sampler} ObservableSource - * and optionally emit the very last upstream item when the upstream or other ObservableSource complete. + * Returns an {@code Observable} that, when the specified {@code sampler} {@link ObservableSource} emits an item or completes, + * emits the most recently emitted item (if any) emitted by the current {@code Observable} since the previous + * emission from the {@code sampler} {@code ObservableSource} + * and optionally emit the very last upstream item when the upstream or other {@code ObservableSource} complete. *

- * + * *

*
Scheduler:
*
This version of {@code sample} does not operate by default on a particular {@link Scheduler}.
*
* *

History: 2.0.5 - experimental - * @param the element type of the sampler ObservableSource + * @param the element type of the sampler {@code ObservableSource} * @param sampler - * the ObservableSource to use for sampling the source ObservableSource + * the {@code ObservableSource} to use for sampling the current {@code Observable} * @param emitLast - * if true and the upstream completes while there is still an unsampled item available, + * if {@code true} and the upstream completes while there is still an unsampled item available, * that item is emitted to downstream before completion - * if false, an unsampled last item is ignored. - * @return an Observable that emits the results of sampling the items emitted by this ObservableSource whenever - * the {@code sampler} ObservableSource emits an item or completes + * if {@code false}, an unsampled last item is ignored. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code sampler} is {@code null} * @see ReactiveX operators documentation: Sample * @since 2.1 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable sample(@NonNull ObservableSource sampler, boolean emitLast) { + public final <@NonNull U> Observable sample(@NonNull ObservableSource sampler, boolean emitLast) { Objects.requireNonNull(sampler, "sampler is null"); return RxJavaPlugins.onAssembly(new ObservableSampleWithObservable<>(this, sampler, emitLast)); } /** - * Returns an Observable that applies a specified accumulator function to the first item emitted by a source - * ObservableSource, then feeds the result of that function along with the second item emitted by the source - * ObservableSource into the same function, and so on until all items have been emitted by the source ObservableSource, - * emitting the result of each of these iterations. + * Returns an {@code Observable} that emits the first value emitted by the current {@code Observable}, then emits one value + * for each subsequent value emitted by the current {@code Observable}. Each emission after the first is the result of + * applying the specified accumulator function to the previous emission and the corresponding value from the current {@code Observable}. *

- * + * *

* This sort of function is sometimes called an accumulator. *

@@ -11788,10 +12331,11 @@ public final Observable sample(@NonNull ObservableSource sampler, bool *
* * @param accumulator - * an accumulator function to be invoked on each item emitted by the source ObservableSource, whose + * an accumulator function to be invoked on each item emitted by the current {@code Observable}, whose * result will be emitted to {@link Observer}s via {@link Observer#onNext onNext} and used in the * next accumulator call - * @return an Observable that emits the results of each call to the accumulator function + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code accumulator} is {@code null} * @see ReactiveX operators documentation: Scan */ @CheckReturnValue @@ -11803,19 +12347,18 @@ public final Observable scan(@NonNull BiFunction accumulator) { } /** - * Returns an Observable that applies a specified accumulator function to the first item emitted by a source - * ObservableSource and a seed value, then feeds the result of that function along with the second item emitted by - * the source ObservableSource into the same function, and so on until all items have been emitted by the source - * ObservableSource, emitting the result of each of these iterations. + * Returns an {@code Observable} that emits the provided initial (seed) value, then emits one value for each value emitted + * by the current {@code Observable}. Each emission after the first is the result of applying the specified accumulator + * function to the previous emission and the corresponding value from the current {@code Observable}. *

- * + * *

* This sort of function is sometimes called an accumulator. *

- * Note that the ObservableSource that results from this method will emit {@code initialValue} as its first + * Note that the {@code Observable} that results from this method will emit {@code initialValue} as its first * emitted item. *

- * Note that the {@code initialValue} is shared among all subscribers to the resulting ObservableSource + * Note that the {@code initialValue} is shared among all subscribers to the resulting {@code Observable} * and may cause problems if it is mutable. To make sure each subscriber gets its own value, defer * the application of this operator via {@link #defer(Supplier)}: *


@@ -11837,32 +12380,31 @@ public final Observable scan(@NonNull BiFunction accumulator) {
      * @param initialValue
      *            the initial (seed) accumulator item
      * @param accumulator
-     *            an accumulator function to be invoked on each item emitted by the source ObservableSource, whose
+     *            an accumulator function to be invoked on each item emitted by the current {@code Observable}, whose
      *            result will be emitted to {@link Observer}s via {@link Observer#onNext onNext} and used in the
      *            next accumulator call
-     * @return an Observable that emits {@code initialValue} followed by the results of each call to the
-     *         accumulator function
+     * @return the new {@code Observable} instance
+     * @throws NullPointerException if {@code initialValue} or {@code accumulator} is {@code null}
      * @see ReactiveX operators documentation: Scan
      */
     @CheckReturnValue
     @SchedulerSupport(SchedulerSupport.NONE)
     @NonNull
-    public final  Observable scan(@NonNull R initialValue, @NonNull BiFunction accumulator) {
+    public final <@NonNull R> Observable scan(@NonNull R initialValue, @NonNull BiFunction accumulator) {
         Objects.requireNonNull(initialValue, "initialValue is null");
         return scanWith(Functions.justSupplier(initialValue), accumulator);
     }
 
     /**
-     * Returns an Observable that applies a specified accumulator function to the first item emitted by a source
-     * ObservableSource and a seed value, then feeds the result of that function along with the second item emitted by
-     * the source ObservableSource into the same function, and so on until all items have been emitted by the source
-     * ObservableSource, emitting the result of each of these iterations.
+     * Returns an {@code Observable} that emits the provided initial (seed) value, then emits one value for each value emitted
+     * by the current {@code Observable}. Each emission after the first is the result of applying the specified accumulator
+     * function to the previous emission and the corresponding value from the current {@code Observable}.
      * 

- * + * *

* This sort of function is sometimes called an accumulator. *

- * Note that the ObservableSource that results from this method will emit the value returned + * Note that the {@code Observable} that results from this method will emit the value returned * by the {@code seedSupplier} as its first item. *

*
Scheduler:
@@ -11871,42 +12413,41 @@ public final Observable scan(@NonNull R initialValue, @NonNull BiFunction * * @param the initial, accumulator and result type * @param seedSupplier - * a Supplier that returns the initial (seed) accumulator item for each individual Observer + * a {@link Supplier} that returns the initial (seed) accumulator item for each individual {@link Observer} * @param accumulator - * an accumulator function to be invoked on each item emitted by the source ObservableSource, whose - * result will be emitted to {@link Observer}s via {@link Observer#onNext onNext} and used in the + * an accumulator function to be invoked on each item emitted by the current {@code Observable}, whose + * result will be emitted to {@code Observer}s via {@link Observer#onNext onNext} and used in the * next accumulator call - * @return an Observable that emits {@code initialValue} followed by the results of each call to the - * accumulator function + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code seedSupplier} or {@code accumulator} is {@code null} * @see ReactiveX operators documentation: Scan */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable scanWith(@NonNull Supplier seedSupplier, @NonNull BiFunction accumulator) { + public final <@NonNull R> Observable scanWith(@NonNull Supplier seedSupplier, @NonNull BiFunction accumulator) { Objects.requireNonNull(seedSupplier, "seedSupplier is null"); Objects.requireNonNull(accumulator, "accumulator is null"); return RxJavaPlugins.onAssembly(new ObservableScanSeed<>(this, seedSupplier, accumulator)); } /** - * Forces an ObservableSource's emissions and notifications to be serialized and for it to obey - * the ObservableSource contract in other ways. + * Forces the current {@code Observable}'s emissions and notifications to be serialized and for it to obey + * the {@code ObservableSource} contract in other ways. *

- * It is possible for an ObservableSource to invoke its Observers' methods asynchronously, perhaps from - * different threads. This could make such an ObservableSource poorly-behaved, in that it might try to invoke + * It is possible for an {@code Observable} to invoke its {@link Observer}s' methods asynchronously, perhaps from + * different threads. This could make such an {@code Observable} poorly-behaved, in that it might try to invoke * {@code onComplete} or {@code onError} before one of its {@code onNext} invocations, or it might call - * {@code onNext} from two different threads concurrently. You can force such an ObservableSource to be + * {@code onNext} from two different threads concurrently. You can force such an {@code Observable} to be * well-behaved and sequential by applying the {@code serialize} method to it. *

- * + * *

*
Scheduler:
*
{@code serialize} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an {@link ObservableSource} that is guaranteed to be well-behaved and to make only serialized calls to - * its observers + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Serialize */ @CheckReturnValue @@ -11917,20 +12458,19 @@ public final Observable serialize() { } /** - * Returns a new {@link ObservableSource} that multicasts (and shares a single subscription to) the original {@link ObservableSource}. As long as - * there is at least one {@link Observer} this {@link ObservableSource} will be subscribed and emitting data. - * When all subscribers have disposed it will dispose the source {@link ObservableSource}. + * Returns a new {@code Observable} that multicasts (and shares a single subscription to) the current {@code Observable}. As long as + * there is at least one {@link Observer}, the current {@code Observable} will stay subscribed and keep emitting signals. + * When all observers have disposed, the operator will dispose the subscription to the current {@code Observable}. *

* This is an alias for {@link #publish()}.{@link ConnectableObservable#refCount() refCount()}. *

- * + * *

*
Scheduler:
*
{@code share} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an {@code ObservableSource} that upon connection causes the source {@code ObservableSource} to emit items - * to its {@link Observer}s + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: RefCount */ @CheckReturnValue @@ -11941,16 +12481,17 @@ public final Observable share() { } /** - * Returns a Maybe that completes if this Observable is empty or emits the single item emitted by this Observable, - * or signals an {@code IllegalArgumentException} if this Observable emits more than one item. + * Returns a {@link Maybe} that completes if the current {@code Observable} is empty or emits the single item + * emitted by the current {@code Observable}, or signals an {@link IllegalArgumentException} if the current + * {@code Observable} emits more than one item. *

- * + * *

*
Scheduler:
*
{@code singleElement} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@link Maybe} that emits the single item emitted by the source ObservableSource + * @return the new {@code Maybe} instance * @see ReactiveX operators documentation: First */ @CheckReturnValue @@ -11961,19 +12502,20 @@ public final Maybe singleElement() { } /** - * Returns a Single that emits the single item emitted by this Observable, if this Observable - * emits only a single item, or a default item if the source ObservableSource emits no items. If the source - * ObservableSource emits more than one item, an {@code IllegalArgumentException} is signalled instead. + * Returns a {@link Single} that emits the single item emitted by the current {@code Observable}, if the current {@code Observable} + * emits only a single item, or a default item if the current {@code Observable} emits no items. If the current + * {@code Observable} emits more than one item, an {@link IllegalArgumentException} is signaled instead. *

- * + * *

*
Scheduler:
*
{@code single} does not operate by default on a particular {@link Scheduler}.
*
* * @param defaultItem - * a default value to emit if the source ObservableSource emits no item - * @return the new Single instance + * a default value to emit if the current {@code Observable} emits no item + * @return the new {@code Single} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @see ReactiveX operators documentation: First */ @CheckReturnValue @@ -11985,18 +12527,18 @@ public final Single single(@NonNull T defaultItem) { } /** - * Returns a Single that emits the single item emitted by this Observable if this Observable + * Returns a {@link Single} that emits the single item emitted by the current {@code Observable} if it * emits only a single item, otherwise - * if this Observable completes without emitting any items or emits more than one item a - * {@link NoSuchElementException} or {@code IllegalArgumentException} will be signalled respectively. + * if the current {@code Observable} completes without emitting any items or emits more than one item a + * {@link NoSuchElementException} or {@link IllegalArgumentException} will be signaled respectively. *

- * + * *

*
Scheduler:
*
{@code singleOrError} does not operate by default on a particular {@link Scheduler}.
*
* - * @return the new Single instance + * @return the new {@code Single} instance * @see ReactiveX operators documentation: First */ @CheckReturnValue @@ -12007,10 +12549,10 @@ public final Single singleOrError() { } /** - * Returns an Observable that skips the first {@code count} items emitted by the source ObservableSource and emits + * Returns an {@code Observable} that skips the first {@code count} items emitted by the current {@code Observable} and emits * the remainder. *

- * + * *

*
Scheduler:
*
This version of {@code skip} does not operate by default on a particular {@link Scheduler}.
@@ -12018,25 +12560,28 @@ public final Single singleOrError() { * * @param count * the number of items to skip - * @return an Observable that is identical to the source ObservableSource except that it does not emit the first - * {@code count} items that the source ObservableSource emits + * @return the new {@code Observable} instance + * @throws IllegalArgumentException if {@code count} is negative * @see ReactiveX operators documentation: Skip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final Observable skip(long count) { - if (count <= 0) { + if (count < 0) { + throw new IllegalArgumentException("count >= 0 expected but it was " + count); + } + if (count == 0) { return RxJavaPlugins.onAssembly(this); } return RxJavaPlugins.onAssembly(new ObservableSkip<>(this, count)); } /** - * Returns an Observable that skips values emitted by the source ObservableSource before a specified time window + * Returns an {@code Observable} that skips values emitted by the current {@code Observable} before a specified time window * elapses. *

- * + * *

*
Scheduler:
*
{@code skip} does not operate on any particular scheduler but uses the current time @@ -12047,8 +12592,8 @@ public final Observable skip(long count) { * the length of the time window to skip * @param unit * the time unit of {@code time} - * @return an Observable that skips values emitted by the source ObservableSource before the time window defined - * by {@code time} elapses and the emits the remainder + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Skip */ @CheckReturnValue @@ -12059,13 +12604,13 @@ public final Observable skip(long time, @NonNull TimeUnit unit) { } /** - * Returns an Observable that skips values emitted by the source ObservableSource before a specified time window + * Returns an {@code Observable} that skips values emitted by the current {@code Observable} before a specified time window * on a specified {@link Scheduler} elapses. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use for the timed skipping
+ *
You specify which {@code Scheduler} this operator will use for the timed skipping
*
* * @param time @@ -12073,9 +12618,9 @@ public final Observable skip(long time, @NonNull TimeUnit unit) { * @param unit * the time unit of {@code time} * @param scheduler - * the {@link Scheduler} on which the timed wait happens - * @return an Observable that skips values emitted by the source ObservableSource before the time window defined - * by {@code time} and {@code scheduler} elapses, and then emits the remainder + * the {@code Scheduler} on which the timed wait happens + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Skip */ @CheckReturnValue @@ -12086,13 +12631,13 @@ public final Observable skip(long time, @NonNull TimeUnit unit, @NonNull Sche } /** - * Returns an Observable that drops a specified number of items from the end of the sequence emitted by the - * source ObservableSource. + * Returns an {@code Observable} that drops a specified number of items from the end of the sequence emitted by the + * current {@code Observable}. *

- * + * *

- * This Observer accumulates a queue long enough to store the first {@code count} items. As more items are - * received, items are taken from the front of the queue and emitted by the returned ObservableSource. This causes + * This {@link Observer} accumulates a queue long enough to store the first {@code count} items. As more items are + * received, items are taken from the front of the queue and emitted by the returned {@code Observable}. This causes * such items to be delayed. *

*
Scheduler:
@@ -12101,10 +12646,9 @@ public final Observable skip(long time, @NonNull TimeUnit unit, @NonNull Sche * * @param count * number of items to drop from the end of the source sequence - * @return an Observable that emits the items emitted by the source ObservableSource except for the dropped ones - * at the end - * @throws IndexOutOfBoundsException - * if {@code count} is less than zero + * @return the new {@code Observable} instance + * @throws IllegalArgumentException + * if {@code count} is negative * @see ReactiveX operators documentation: SkipLast */ @CheckReturnValue @@ -12112,7 +12656,7 @@ public final Observable skip(long time, @NonNull TimeUnit unit, @NonNull Sche @NonNull public final Observable skipLast(int count) { if (count < 0) { - throw new IndexOutOfBoundsException("count >= 0 required but it was " + count); + throw new IllegalArgumentException("count >= 0 required but it was " + count); } if (count == 0) { return RxJavaPlugins.onAssembly(this); @@ -12121,24 +12665,24 @@ public final Observable skipLast(int count) { } /** - * Returns an Observable that drops items emitted by the source ObservableSource during a specified time window + * Returns an {@code Observable} that drops items emitted by the current {@code Observable} during a specified time window * before the source completes. *

- * + * *

* Note: this action will cache the latest items arriving in the specified time window. *

*
Scheduler:
*
{@code skipLast} does not operate on any particular scheduler but uses the current time - * from the {@code computation} {@link Scheduler}.
+ * from the {@code trampoline} {@link Scheduler}.
*
* * @param time * the length of the time window * @param unit * the time unit of {@code time} - * @return an Observable that drops those items emitted by the source ObservableSource in a time window before the - * source completes defined by {@code time} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: SkipLast */ @CheckReturnValue @@ -12149,10 +12693,10 @@ public final Observable skipLast(long time, @NonNull TimeUnit unit) { } /** - * Returns an Observable that drops items emitted by the source ObservableSource during a specified time window + * Returns an {@code Observable} that drops items emitted by the current {@code Observable} during a specified time window * before the source completes. *

- * + * *

* Note: this action will cache the latest items arriving in the specified time window. *

@@ -12166,10 +12710,10 @@ public final Observable skipLast(long time, @NonNull TimeUnit unit) { * @param unit * the time unit of {@code time} * @param delayError - * if true, an exception signalled by the current Observable is delayed until the regular elements are consumed - * by the downstream; if false, an exception is immediately signalled and all regular elements dropped - * @return an Observable that drops those items emitted by the source ObservableSource in a time window before the - * source completes defined by {@code time} + * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed + * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: SkipLast */ @CheckReturnValue @@ -12180,10 +12724,10 @@ public final Observable skipLast(long time, @NonNull TimeUnit unit, boolean d } /** - * Returns an Observable that drops items emitted by the source ObservableSource during a specified time window + * Returns an {@code Observable} that drops items emitted by the current {@code Observable} during a specified time window * (defined on a specified scheduler) before the source completes. *

- * + * *

* Note: this action will cache the latest items arriving in the specified time window. *

@@ -12197,8 +12741,8 @@ public final Observable skipLast(long time, @NonNull TimeUnit unit, boolean d * the time unit of {@code time} * @param scheduler * the scheduler used as the time source - * @return an Observable that drops those items emitted by the source ObservableSource in a time window before the - * source completes defined by {@code time} and {@code scheduler} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: SkipLast */ @CheckReturnValue @@ -12209,10 +12753,10 @@ public final Observable skipLast(long time, @NonNull TimeUnit unit, @NonNull } /** - * Returns an Observable that drops items emitted by the source ObservableSource during a specified time window + * Returns an {@code Observable} that drops items emitted by the current {@code Observable} during a specified time window * (defined on a specified scheduler) before the source completes. *

- * + * *

* Note: this action will cache the latest items arriving in the specified time window. *

@@ -12227,10 +12771,10 @@ public final Observable skipLast(long time, @NonNull TimeUnit unit, @NonNull * @param scheduler * the scheduler used as the time source * @param delayError - * if true, an exception signalled by the current Observable is delayed until the regular elements are consumed - * by the downstream; if false, an exception is immediately signalled and all regular elements dropped - * @return an Observable that drops those items emitted by the source ObservableSource in a time window before the - * source completes defined by {@code time} and {@code scheduler} + * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed + * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: SkipLast */ @CheckReturnValue @@ -12241,10 +12785,10 @@ public final Observable skipLast(long time, @NonNull TimeUnit unit, @NonNull } /** - * Returns an Observable that drops items emitted by the source ObservableSource during a specified time window + * Returns an {@code Observable} that drops items emitted by the current {@code Observable} during a specified time window * (defined on a specified scheduler) before the source completes. *

- * + * *

* Note: this action will cache the latest items arriving in the specified time window. *

@@ -12259,12 +12803,13 @@ public final Observable skipLast(long time, @NonNull TimeUnit unit, @NonNull * @param scheduler * the scheduler used as the time source * @param delayError - * if true, an exception signalled by the current Observable is delayed until the regular elements are consumed - * by the downstream; if false, an exception is immediately signalled and all regular elements dropped + * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed + * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped * @param bufferSize * the hint about how many elements to expect to be skipped - * @return an Observable that drops those items emitted by the source ObservableSource in a time window before the - * source completes defined by {@code time} and {@code scheduler} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: SkipLast */ @CheckReturnValue @@ -12280,45 +12825,45 @@ public final Observable skipLast(long time, @NonNull TimeUnit unit, @NonNull } /** - * Returns an Observable that skips items emitted by the source ObservableSource until a second ObservableSource emits + * Returns an {@code Observable} that skips items emitted by the current {@code Observable} until a second {@link ObservableSource} emits * an item. *

- * + * *

*
Scheduler:
*
{@code skipUntil} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the element type of the other ObservableSource + * @param the element type of the other {@code ObservableSource} * @param other - * the second ObservableSource that has to emit an item before the source ObservableSource's elements begin - * to be mirrored by the resulting ObservableSource - * @return an Observable that skips items from the source ObservableSource until the second ObservableSource emits an - * item, then emits the remaining items + * the second {@code ObservableSource} that has to emit an item before the current {@code Observable}'s elements begin + * to be mirrored by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: SkipUntil */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable skipUntil(@NonNull ObservableSource other) { + public final <@NonNull U> Observable skipUntil(@NonNull ObservableSource other) { Objects.requireNonNull(other, "other is null"); return RxJavaPlugins.onAssembly(new ObservableSkipUntil<>(this, other)); } /** - * Returns an Observable that skips all items emitted by the source ObservableSource as long as a specified - * condition holds true, but emits all further source items as soon as the condition becomes false. + * Returns an {@code Observable} that skips all items emitted by the current {@code Observable} as long as a specified + * condition holds {@code true}, but emits all further source items as soon as the condition becomes {@code false}. *

- * + * *

*
Scheduler:
*
{@code skipWhile} does not operate by default on a particular {@link Scheduler}.
*
* * @param predicate - * a function to test each item emitted from the source ObservableSource - * @return an Observable that begins emitting items emitted by the source ObservableSource when the specified - * predicate becomes false + * a function to test each item emitted from the current {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @see ReactiveX operators documentation: SkipWhile */ @CheckReturnValue @@ -12330,14 +12875,14 @@ public final Observable skipWhile(@NonNull Predicate predicate) { } /** - * Returns an Observable that emits the events emitted by source ObservableSource, in a - * sorted order. Each item emitted by the ObservableSource must implement {@link Comparable} with respect to all + * Returns an {@code Observable} that emits the events emitted by the current {@code Observable}, in a + * sorted order. Each item emitted by the current {@code Observable} must implement {@link Comparable} with respect to all * other items in the sequence. *

* *

- * If any item emitted by this Observable does not implement {@link Comparable} with respect to - * all other items emitted by this Observable, no items will be emitted and the + * If any item emitted by the current {@code Observable} does not implement {@code Comparable} with respect to + * all other items emitted by the current {@code Observable}, no items will be emitted and the * sequence is terminated with a {@link ClassCastException}. * *

Note that calling {@code sorted} with long, non-terminating or infinite sources @@ -12347,7 +12892,7 @@ public final Observable skipWhile(@NonNull Predicate predicate) { *

Scheduler:
*
{@code sorted} does not operate by default on a particular {@link Scheduler}.
*
- * @return an Observable that emits the items emitted by the source ObservableSource in sorted order + * @return the new {@code Observable} instance */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -12357,7 +12902,7 @@ public final Observable sorted() { } /** - * Returns an Observable that emits the events emitted by source ObservableSource, in a + * Returns an {@code Observable} that emits the events emitted by the current {@code Observable}, in a * sorted order based on a specified comparison function. * *

Note that calling {@code sorted} with long, non-terminating or infinite sources @@ -12368,33 +12913,34 @@ public final Observable sorted() { *

{@code sorted} does not operate by default on a particular {@link Scheduler}.
*
* - * @param sortFunction - * a function that compares two items emitted by the source ObservableSource and returns an Integer + * @param comparator + * a function that compares two items emitted by the current {@code Observable} and returns an {@code int} * that indicates their sort order - * @return an Observable that emits the items emitted by the source ObservableSource in sorted order + * @throws NullPointerException if {@code comparator} is {@code null} + * @return the new {@code Observable} instance */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable sorted(@NonNull Comparator sortFunction) { - Objects.requireNonNull(sortFunction, "sortFunction is null"); - return toList().toObservable().map(Functions.listSorter(sortFunction)).flatMapIterable(Functions.identity()); + public final Observable sorted(@NonNull Comparator comparator) { + Objects.requireNonNull(comparator, "comparator is null"); + return toList().toObservable().map(Functions.listSorter(comparator)).flatMapIterable(Functions.identity()); } /** - * Returns an Observable that emits the items in a specified {@link Iterable} before it begins to emit items - * emitted by the source ObservableSource. + * Returns an {@code Observable} that emits the items in a specified {@link Iterable} before it begins to emit items + * emitted by the current {@code Observable}. *

- * + * *

*
Scheduler:
*
{@code startWithIterable} does not operate by default on a particular {@link Scheduler}.
*
* * @param items - * an Iterable that contains the items you want the modified ObservableSource to emit first - * @return an Observable that emits the items in the specified {@link Iterable} and then emits the items - * emitted by the source ObservableSource + * an {@code Iterable} that contains the items you want the resulting {@code Observable} to emit first + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code items} is {@code null} * @see ReactiveX operators documentation: StartWith * @since 3.0.0 * @see #startWithItem(Object) @@ -12408,19 +12954,85 @@ public final Observable startWithIterable(@NonNull Iterable item } /** - * Returns an Observable that emits the items in a specified {@link ObservableSource} before it begins to emit - * items emitted by the source ObservableSource. + * Returns an {@code Observable} which first runs the other {@link CompletableSource} + * then the current {@code Observable} if the other completed normally. + *

+ * + *

+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code CompletableSource} to run first + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final Observable startWith(@NonNull CompletableSource other) { + Objects.requireNonNull(other, "other is null"); + return Observable.concat(Completable.wrap(other).toObservable(), this); + } + + /** + * Returns an {@code Observable} which first runs the other {@link SingleSource} + * then the current {@code Observable} if the other succeeded normally. + *

+ * + *

+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code SingleSource} to run first + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final Observable startWith(@NonNull SingleSource other) { + Objects.requireNonNull(other, "other is null"); + return Observable.concat(Single.wrap(other).toObservable(), this); + } + + /** + * Returns an {@code Observable} which first runs the other {@link MaybeSource} + * then the current {@code Observable} if the other succeeded or completed normally. + *

+ * + *

+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code MaybeSource} to run first + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final Observable startWith(@NonNull MaybeSource other) { + Objects.requireNonNull(other, "other is null"); + return Observable.concat(Maybe.wrap(other).toObservable(), this); + } + + /** + * Returns an {@code Observable} that emits the items in a specified {@link ObservableSource} before it begins to emit + * items emitted by the current {@code Observable}. *

- * + * *

*
Scheduler:
*
{@code startWith} does not operate by default on a particular {@link Scheduler}.
*
* * @param other - * an ObservableSource that contains the items you want the modified ObservableSource to emit first - * @return an Observable that emits the items in the specified {@link ObservableSource} and then emits the items - * emitted by the source ObservableSource + * an {@code ObservableSource} that contains the items you want the modified {@code ObservableSource} to emit first + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: StartWith */ @CheckReturnValue @@ -12432,8 +13044,8 @@ public final Observable startWith(@NonNull ObservableSource othe } /** - * Returns an Observable that emits a specified item before it begins to emit items emitted by the source - * ObservableSource. + * Returns an {@code Observable} that emits a specified item before it begins to emit items emitted by the current + * {@code Observable}. *

* *

@@ -12443,8 +13055,8 @@ public final Observable startWith(@NonNull ObservableSource othe * * @param item * the item to emit first - * @return an Observable that emits the specified item before it begins to emit items emitted by the source - * ObservableSource + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code item} is {@code null} * @see ReactiveX operators documentation: StartWith * @see #startWithArray(Object...) * @see #startWithIterable(Iterable) @@ -12454,15 +13066,14 @@ public final Observable startWith(@NonNull ObservableSource othe @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final Observable startWithItem(@NonNull T item) { - Objects.requireNonNull(item, "item is null"); return concatArray(just(item), this); } /** - * Returns an Observable that emits the specified items before it begins to emit items emitted by the source - * ObservableSource. + * Returns an {@code Observable} that emits the specified items before it begins to emit items emitted by the current + * {@code Observable}. *

- * + * *

*
Scheduler:
*
{@code startWithArray} does not operate by default on a particular {@link Scheduler}.
@@ -12470,8 +13081,8 @@ public final Observable startWithItem(@NonNull T item) { * * @param items * the array of values to emit first - * @return an Observable that emits the specified items before it begins to emit items emitted by the source - * ObservableSource + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code items} is {@code null} * @see ReactiveX operators documentation: StartWith * @see #startWithItem(Object) * @see #startWithIterable(Iterable) @@ -12489,19 +13100,19 @@ public final Observable startWithArray(@NonNull T... items) { } /** - * Subscribes to an ObservableSource and ignores {@code onNext} and {@code onComplete} emissions. + * Subscribes to the current {@code Observable} and ignores {@code onNext} and {@code onComplete} emissions. *

- * If the Observable emits an error, it is wrapped into an - * {@link io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException OnErrorNotImplementedException} - * and routed to the RxJavaPlugins.onError handler. + * If the {@code Observable} emits an error, it is wrapped into an + * {@link OnErrorNotImplementedException} + * and routed to the {@link RxJavaPlugins#onError(Throwable)} handler. *

*
Scheduler:
*
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@link Disposable} reference with which the caller can stop receiving items before - * the ObservableSource has finished sending them + * @return the new {@link Disposable} instance that can be used to dispose the subscription at any time * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, Action, DisposableContainer) */ @SchedulerSupport(SchedulerSupport.NONE) @NonNull @@ -12510,23 +13121,23 @@ public final Disposable subscribe() { } /** - * Subscribes to an ObservableSource and provides a callback to handle the items it emits. + * Subscribes to the current {@code Observable} and provides a callback to handle the items it emits. *

- * If the Observable emits an error, it is wrapped into an - * {@link io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException OnErrorNotImplementedException} - * and routed to the RxJavaPlugins.onError handler. + * If the {@code Observable} emits an error, it is wrapped into an + * {@link OnErrorNotImplementedException} + * and routed to the {@link RxJavaPlugins#onError(Throwable)} handler. *

*
Scheduler:
*
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
* * @param onNext - * the {@code Consumer} you have designed to accept emissions from the ObservableSource - * @return a {@link Disposable} reference with which the caller can stop receiving items before - * the ObservableSource has finished sending them + * the {@code Consumer} you have designed to accept emissions from the current {@code Observable} + * @return the new {@link Disposable} instance that can be used to dispose the subscription at any time * @throws NullPointerException - * if {@code onNext} is null + * if {@code onNext} is {@code null} * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, Action, DisposableContainer) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -12536,24 +13147,23 @@ public final Disposable subscribe(@NonNull Consumer onNext) { } /** - * Subscribes to an ObservableSource and provides callbacks to handle the items it emits and any error - * notification it issues. + * Subscribes to the current {@code Observable} and provides callbacks to handle the items it emits and any error + * notification it signals. *
*
Scheduler:
*
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
* * @param onNext - * the {@code Consumer} you have designed to accept emissions from the ObservableSource + * the {@code Consumer} you have designed to accept emissions from the current {@code Observable} * @param onError - * the {@code Consumer} you have designed to accept any error notification from the - * ObservableSource - * @return a {@link Disposable} reference with which the caller can stop receiving items before - * the ObservableSource has finished sending them - * @see ReactiveX operators documentation: Subscribe + * the {@code Consumer} you have designed to accept any error notification from the current + * {@code Observable} + * @return the new {@link Disposable} instance that can be used to dispose the subscription at any time * @throws NullPointerException - * if {@code onNext} is null, or - * if {@code onError} is null + * if {@code onNext} or {@code onError} is {@code null} + * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, Action, DisposableContainer) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -12563,28 +13173,26 @@ public final Disposable subscribe(@NonNull Consumer onNext, @NonNull } /** - * Subscribes to an ObservableSource and provides callbacks to handle the items it emits and any error or - * completion notification it issues. + * Subscribes to the current {@code Observable} and provides callbacks to handle the items it emits and any error or + * completion notification it signals. *
*
Scheduler:
*
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
* * @param onNext - * the {@code Consumer} you have designed to accept emissions from the ObservableSource + * the {@code Consumer} you have designed to accept emissions from the current {@code Observable} * @param onError - * the {@code Consumer} you have designed to accept any error notification from the - * ObservableSource + * the {@code Consumer} you have designed to accept any error notification from the current + * {@code Observable} * @param onComplete - * the {@code Action} you have designed to accept a completion notification from the - * ObservableSource - * @return a {@link Disposable} reference with which the caller can stop receiving items before - * the ObservableSource has finished sending them + * the {@link Action} you have designed to accept a completion notification from the current + * {@code Observable} + * @return the new {@link Disposable} instance that can be used to dispose the subscription at any time * @throws NullPointerException - * if {@code onNext} is null, or - * if {@code onError} is null, or - * if {@code onComplete} is null + * if {@code onNext}, {@code onError} or {@code onComplete} is {@code null} * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, Action, DisposableContainer) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -12602,6 +13210,47 @@ public final Disposable subscribe(@NonNull Consumer onNext, @NonNull return ls; } + /** + * Wraps the given onXXX callbacks into a {@link Disposable} {@link Observer}, + * adds it to the given {@code DisposableContainer} and ensures, that if the upstream + * terminates or this particular {@code Disposable} is disposed, the {@code Observer} is removed + * from the given container. + *

+ * The {@code Observer} will be removed after the callback for the terminal event has been invoked. + *

+ *
Scheduler:
+ *
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param onNext the callback for upstream items + * @param onError the callback for an upstream error if any + * @param onComplete the callback for the upstream completion if any + * @param container the {@code DisposableContainer} (such as {@link CompositeDisposable}) to add and remove the + * created {@code Disposable} {@code Observer} + * @return the {@code Disposable} that allows disposing the particular subscription. + * @throws NullPointerException + * if {@code onNext}, {@code onError}, + * {@code onComplete} or {@code container} is {@code null} + * @since 3.1.0 + */ + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Disposable subscribe( + @NonNull Consumer onNext, + @NonNull Consumer onError, + @NonNull Action onComplete, + @NonNull DisposableContainer container) { + Objects.requireNonNull(onNext, "onNext is null"); + Objects.requireNonNull(onError, "onError is null"); + Objects.requireNonNull(onComplete, "onComplete is null"); + Objects.requireNonNull(container, "container is null"); + + DisposableAutoReleaseObserver observer = new DisposableAutoReleaseObserver<>( + container, onNext, onError, onComplete); + container.add(observer); + subscribe(observer); + return observer; + } + @SchedulerSupport(SchedulerSupport.NONE) @Override public final void subscribe(@NonNull Observer observer) { @@ -12632,13 +13281,13 @@ public final void subscribe(@NonNull Observer observer) { *

There is no need to call any of the plugin hooks on the current {@code Observable} instance or * the {@code Observer}; all hooks and basic safeguards have been * applied by {@link #subscribe(Observer)} before this method gets called. - * @param observer the incoming Observer, never null + * @param observer the incoming {@code Observer}, never {@code null} */ protected abstract void subscribeActual(@NonNull Observer observer); /** - * Subscribes a given Observer (subclass) to this Observable and returns the given - * Observer as is. + * Subscribes a given {@link Observer} (subclass) to the current {@code Observable} and returns the given + * {@code Observer} instance as is. *

Usage example: *


      * Observable<Integer> source = Observable.range(1, 10);
@@ -12654,10 +13303,10 @@ public final void subscribe(@NonNull Observer observer) {
      *  
Scheduler:
*
{@code subscribeWith} does not operate by default on a particular {@link Scheduler}.
*
- * @param the type of the Observer to use and return - * @param observer the Observer (subclass) to use and return, not null + * @param the type of the {@code Observer} to use and return + * @param observer the {@code Observer} (subclass) to use and return, not {@code null} * @return the input {@code observer} - * @throws NullPointerException if {@code observer} is null + * @throws NullPointerException if {@code observer} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -12669,18 +13318,18 @@ public final void subscribe(@NonNull Observer observer) { } /** - * Asynchronously subscribes Observers to this ObservableSource on the specified {@link Scheduler}. + * Asynchronously subscribes {@link Observer}s to the current {@code Observable} on the specified {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param scheduler - * the {@link Scheduler} to perform subscription actions on - * @return the source ObservableSource modified so that its subscriptions happen on the - * specified {@link Scheduler} + * the {@code Scheduler} to perform subscription actions on + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: SubscribeOn * @see RxJava Threading Examples * @see #observeOn @@ -12694,19 +13343,19 @@ public final Observable subscribeOn(@NonNull Scheduler scheduler) { } /** - * Returns an Observable that emits the items emitted by the source ObservableSource or the items of an alternate - * ObservableSource if the source ObservableSource is empty. + * Returns an {@code Observable} that emits the items emitted by the current {@code Observable} or the items of an alternate + * {@link ObservableSource} if the current {@code Observable} is empty. *

- * + * *

*
Scheduler:
*
{@code switchIfEmpty} does not operate by default on a particular {@link Scheduler}.
*
* * @param other - * the alternate ObservableSource to subscribe to if the source does not emit any items - * @return an ObservableSource that emits the items emitted by the source ObservableSource or the items of an - * alternate ObservableSource if the source ObservableSource is empty. + * the alternate {@code ObservableSource} to subscribe to if the source does not emit any items + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} * @since 1.1.0 */ @CheckReturnValue @@ -12718,62 +13367,65 @@ public final Observable switchIfEmpty(@NonNull ObservableSource } /** - * Returns a new ObservableSource by applying a function that you supply to each item emitted by the source - * ObservableSource that returns an ObservableSource, and then emitting the items emitted by the most recently emitted - * of these ObservableSources. + * Returns a new {@code Observable} by applying a function that you supply to each item emitted by the current + * {@code Observable} that returns an {@link ObservableSource}, and then emitting the items emitted by the most recently emitted + * of these {@code ObservableSource}s. *

- * The resulting ObservableSource completes if both the upstream ObservableSource and the last inner ObservableSource, if any, complete. - * If the upstream ObservableSource signals an onError, the inner ObservableSource is disposed and the error delivered in-sequence. + * The resulting {@code Observable} completes if both the current {@code Observable} and the last inner {@code ObservableSource}, if any, complete. + * If the current {@code Observable} signals an {@code onError}, the inner {@code ObservableSource} is disposed and the error delivered in-sequence. *

- * + * *

*
Scheduler:
*
{@code switchMap} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the element type of the inner ObservableSources and the output + * @param the element type of the inner {@code ObservableSource}s and the output * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns an - * ObservableSource - * @return an Observable that emits the items emitted by the ObservableSource returned from applying {@code func} to the most recently emitted item emitted by the source ObservableSource + * a function that, when applied to an item emitted by the current {@code Observable}, returns an + * {@code ObservableSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap * @see #switchMapDelayError(Function) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable switchMap(@NonNull Function> mapper) { + public final <@NonNull R> Observable switchMap(@NonNull Function> mapper) { return switchMap(mapper, bufferSize()); } /** - * Returns a new ObservableSource by applying a function that you supply to each item emitted by the source - * ObservableSource that returns an ObservableSource, and then emitting the items emitted by the most recently emitted - * of these ObservableSources. + * Returns a new {@code Observable} by applying a function that you supply to each item emitted by the current + * {@code Observable} that returns an {@link ObservableSource}, and then emitting the items emitted by the most recently emitted + * of these {@code ObservableSource}s. *

- * The resulting ObservableSource completes if both the upstream ObservableSource and the last inner ObservableSource, if any, complete. - * If the upstream ObservableSource signals an onError, the inner ObservableSource is disposed and the error delivered in-sequence. + * The resulting {@code Observable} completes if both the current {@code Observable} and the last inner {@code ObservableSource}, if any, complete. + * If the current {@code Observable} signals an {@code onError}, the inner {@code ObservableSource} is disposed and the error delivered in-sequence. *

- * + * *

*
Scheduler:
*
{@code switchMap} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the element type of the inner ObservableSources and the output + * @param the element type of the inner {@code ObservableSource}s and the output * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns an - * ObservableSource + * a function that, when applied to an item emitted by the current {@code Observable}, returns an + * {@code ObservableSource} * @param bufferSize - * the number of elements to prefetch from the current active inner ObservableSource - * @return an Observable that emits the items emitted by the ObservableSource returned from applying {@code func} to the most recently emitted item emitted by the source ObservableSource + * the number of elements expected from the current active inner {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: FlatMap * @see #switchMapDelayError(Function, int) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable switchMap(@NonNull Function> mapper, int bufferSize) { + public final <@NonNull R> Observable switchMap(@NonNull Function> mapper, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); if (this instanceof ScalarSupplier) { @@ -12788,36 +13440,37 @@ public final Observable switchMap(@NonNull Function - * + * *

* Since a {@code CompletableSource} doesn't produce any items, the resulting reactive type of * this operator is a {@link Completable} that can only indicate successful completion or * a failure in any of the inner {@code CompletableSource}s or the failure of the current - * {@link Observable}. + * {@code Observable}. *

*
Scheduler:
*
{@code switchMapCompletable} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If either this {@code Observable} or the active {@code CompletableSource} signals an {@code onError}, - * the resulting {@code Completable} is terminated immediately with that {@code Throwable}. + *
If either the current {@code Observable} or the active {@code CompletableSource} signals an {@code onError}, + * the resulting {@code Completable} is terminated immediately with that {@link Throwable}. * Use the {@link #switchMapCompletableDelayError(Function)} to delay such inner failures until * every inner {@code CompletableSource}s and the main {@code Observable} terminates in some fashion. * If they fail concurrently, the operator may combine the {@code Throwable}s into a - * {@link io.reactivex.rxjava3.exceptions.CompositeException CompositeException} + * {@link CompositeException} * and signal it to the downstream instead. If any inactivated (switched out) {@code CompletableSource} - * signals an {@code onError} late, the {@code Throwable}s will be signalled to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. + * signals an {@code onError} late, the {@code Throwable}s will be signaled to the global error handler via + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. *
*
*

History: 2.1.11 - experimental * @param mapper the function called with each upstream item and should return a - * {@link CompletableSource} to be subscribed to and awaited for + * {@code CompletableSource} to be subscribed to and awaited for * (non blockingly) for its terminal event - * @return the new Completable instance + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see #switchMapCompletableDelayError(Function) * @since 2.2 */ @@ -12840,27 +13493,28 @@ public final Completable switchMapCompletable(@NonNull Function *

Scheduler:
*
{@code switchMapCompletableDelayError} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
Errors of this {@code Observable} and all the {@code CompletableSource}s, who had the chance + *
The errors of the current {@code Observable} and all the {@code CompletableSource}s, who had the chance * to run to their completion, are delayed until * all of them terminate in some fashion. At this point, if there was only one failure, the respective - * {@code Throwable} is emitted to the downstream. It there were more than one failures, the - * operator combines all {@code Throwable}s into a {@link io.reactivex.rxjava3.exceptions.CompositeException CompositeException} + * {@link Throwable} is emitted to the downstream. It there were more than one failures, the + * operator combines all {@code Throwable}s into a {@link CompositeException} * and signals that to the downstream. * If any inactivated (switched out) {@code CompletableSource} - * signals an {@code onError} late, the {@code Throwable}s will be signalled to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. + * signals an {@code onError} late, the {@code Throwable}s will be signaled to the global error handler via + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. *
*
*

History: 2.1.11 - experimental * @param mapper the function called with each upstream item and should return a - * {@link CompletableSource} to be subscribed to and awaited for + * {@code CompletableSource} to be subscribed to and awaited for * (non blockingly) for its terminal event - * @return the new Completable instance + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see #switchMapCompletable(Function) * @since 2.2 */ @@ -12873,38 +13527,39 @@ public final Completable switchMapCompletableDelayError(@NonNull Function - * + * *

*
Scheduler:
*
{@code switchMapMaybe} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
This operator terminates with an {@code onError} if this {@code Observable} or any of + *
This operator terminates with an {@code onError} if the current {@code Observable} or any of * the inner {@code MaybeSource}s fail while they are active. When this happens concurrently, their - * individual {@code Throwable} errors may get combined and emitted as a single - * {@link io.reactivex.rxjava3.exceptions.CompositeException CompositeException}. Otherwise, a late - * (i.e., inactive or switched out) {@code onError} from this {@code Observable} or from any of + * individual {@link Throwable} errors may get combined and emitted as a single + * {@link CompositeException}. Otherwise, a late + * (i.e., inactive or switched out) {@code onError} from the current {@code Observable} or from any of * the inner {@code MaybeSource}s will be forwarded to the global error handler via - * {@link io.reactivex.rxjava3.plugins.RxJavaPlugins#onError(Throwable)} as - * {@link io.reactivex.rxjava3.exceptions.UndeliverableException UndeliverableException}
+ * {@link RxJavaPlugins#onError(Throwable)} as + * {@link UndeliverableException} *
*

History: 2.1.11 - experimental * @param the output value type * @param mapper the function called with the current upstream event and should * return a {@code MaybeSource} to replace the current active inner source * and get subscribed to. - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see #switchMapMaybeDelayError(Function) * @since 2.2 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable switchMapMaybe(@NonNull Function> mapper) { + public final <@NonNull R> Observable switchMapMaybe(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new ObservableSwitchMapMaybe<>(this, mapper, false)); } @@ -12912,9 +13567,9 @@ public final Observable switchMapMaybe(@NonNull Function - * + * *

*
Scheduler:
*
{@code switchMapMaybeDelayError} does not operate by default on a particular {@link Scheduler}.
@@ -12924,37 +13579,39 @@ public final Observable switchMapMaybe(@NonNull Function Observable switchMapMaybeDelayError(@NonNull Function> mapper) { + public final <@NonNull R> Observable switchMapMaybeDelayError(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new ObservableSwitchMapMaybe<>(this, mapper, true)); } /** - * Returns a new ObservableSource by applying a function that you supply to each item emitted by the source - * ObservableSource that returns a SingleSource, and then emitting the item emitted by the most recently emitted - * of these SingleSources. + * Returns a new {@code Observable} by applying a function that you supply to each item emitted by the current + * {@code Observable} that returns a {@link SingleSource}, and then emitting the item emitted by the most recently emitted + * of these {@code SingleSource}s. *

- * The resulting ObservableSource completes if both the upstream ObservableSource and the last inner SingleSource, if any, complete. - * If the upstream ObservableSource signals an onError, the inner SingleSource is disposed and the error delivered in-sequence. + * The resulting {@code Observable} completes if both the current {@code Observable} and the last inner {@code SingleSource}, if any, complete. + * If the current {@code Observable} signals an {@code onError}, the inner {@code SingleSource} is disposed and the error delivered in-sequence. *

- * + * *

*
Scheduler:
*
{@code switchMapSingle} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.0.8 - experimental - * @param the element type of the inner SingleSources and the output + * @param the element type of the inner {@code SingleSource}s and the output * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns a - * SingleSource - * @return an Observable that emits the item emitted by the SingleSource returned from applying {@code func} to the most recently emitted item emitted by the source ObservableSource + * a function that, when applied to an item emitted by the current {@code Observable}, returns a + * {@code SingleSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap * @see #switchMapSingleDelayError(Function) * @since 2.2 @@ -12962,19 +13619,19 @@ public final Observable switchMapMaybeDelayError(@NonNull Function Observable switchMapSingle(@NonNull Function> mapper) { + public final <@NonNull R> Observable switchMapSingle(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new ObservableSwitchMapSingle<>(this, mapper, false)); } /** - * Returns a new ObservableSource by applying a function that you supply to each item emitted by the source - * ObservableSource that returns a SingleSource, and then emitting the item emitted by the most recently emitted - * of these SingleSources and delays any error until all SingleSources terminate. + * Returns a new {@code Observable} by applying a function that you supply to each item emitted by the current + * {@code Observable} that returns a {@link SingleSource}, and then emitting the item emitted by the most recently emitted + * of these {@code SingleSource}s and delays any error until all {@code SingleSource}s terminate. *

- * The resulting ObservableSource completes if both the upstream ObservableSource and the last inner SingleSource, if any, complete. - * If the upstream ObservableSource signals an onError, the termination of the last inner SingleSource will emit that error as is - * or wrapped into a CompositeException along with the other possible errors the former inner SingleSources signalled. + * The resulting {@code Observable} completes if both the current {@code Observable} and the last inner {@code SingleSource}, if any, complete. + * If the current {@code Observable} signals an {@code onError}, the termination of the last inner {@code SingleSource} will emit that error as is + * or wrapped into a {@link CompositeException} along with the other possible errors the former inner {@code SingleSource}s signaled. *

* *

@@ -12982,11 +13639,12 @@ public final Observable switchMapSingle(@NonNull Function{@code switchMapSingleDelayError} does not operate by default on a particular {@link Scheduler}. *
*

History: 2.0.8 - experimental - * @param the element type of the inner SingleSources and the output + * @param the element type of the inner {@code SingleSource}s and the output * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns a - * SingleSource - * @return an Observable that emits the item emitted by the SingleSource returned from applying {@code func} to the most recently emitted item emitted by the source ObservableSource + * a function that, when applied to an item emitted by the current {@code Observable}, returns a + * {@code SingleSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap * @see #switchMapSingle(Function) * @since 2.2 @@ -12994,31 +13652,32 @@ public final Observable switchMapSingle(@NonNull Function Observable switchMapSingleDelayError(@NonNull Function> mapper) { + public final <@NonNull R> Observable switchMapSingleDelayError(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new ObservableSwitchMapSingle<>(this, mapper, true)); } /** - * Returns a new ObservableSource by applying a function that you supply to each item emitted by the source - * ObservableSource that returns an ObservableSource, and then emitting the items emitted by the most recently emitted - * of these ObservableSources and delays any error until all ObservableSources terminate. + * Returns a new {@code Observable} by applying a function that you supply to each item emitted by the current + * {@code Observable} that returns an {@link ObservableSource}, and then emitting the items emitted by the most recently emitted + * of these {@code ObservableSource}s and delays any error until all {@code ObservableSource}s terminate. *

- * The resulting ObservableSource completes if both the upstream ObservableSource and the last inner ObservableSource, if any, complete. - * If the upstream ObservableSource signals an onError, the termination of the last inner ObservableSource will emit that error as is - * or wrapped into a CompositeException along with the other possible errors the former inner ObservableSources signalled. + * The resulting {@code Observable} completes if both the current {@code Observable} and the last inner {@code ObservableSource}, if any, complete. + * If the current {@code Observable} signals an {@code onError}, the termination of the last inner {@code ObservableSource} will emit that error as is + * or wrapped into a {@link CompositeException} along with the other possible errors the former inner {@code ObservableSource}s signaled. *

- * + * *

*
Scheduler:
*
{@code switchMapDelayError} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the element type of the inner ObservableSources and the output + * @param the element type of the inner {@code ObservableSource}s and the output * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns an - * ObservableSource - * @return an Observable that emits the items emitted by the ObservableSource returned from applying {@code func} to the most recently emitted item emitted by the source ObservableSource + * a function that, when applied to an item emitted by the current {@code Observable}, returns an + * {@code ObservableSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap * @see #switchMap(Function) * @since 2.0 @@ -13026,32 +13685,34 @@ public final Observable switchMapSingleDelayError(@NonNull Function Observable switchMapDelayError(@NonNull Function> mapper) { + public final <@NonNull R> Observable switchMapDelayError(@NonNull Function> mapper) { return switchMapDelayError(mapper, bufferSize()); } /** - * Returns a new ObservableSource by applying a function that you supply to each item emitted by the source - * ObservableSource that returns an ObservableSource, and then emitting the items emitted by the most recently emitted - * of these ObservableSources and delays any error until all ObservableSources terminate. + * Returns a new {@code Observable} by applying a function that you supply to each item emitted by the current + * {@code Observable} that returns an {@link ObservableSource}, and then emitting the items emitted by the most recently emitted + * of these {@code ObservableSource}s and delays any error until all {@code ObservableSource}s terminate. *

- * The resulting ObservableSource completes if both the upstream ObservableSource and the last inner ObservableSource, if any, complete. - * If the upstream ObservableSource signals an onError, the termination of the last inner ObservableSource will emit that error as is - * or wrapped into a CompositeException along with the other possible errors the former inner ObservableSources signalled. + * The resulting {@code Observable} completes if both the current {@code Observable} and the last inner {@code ObservableSource}, if any, complete. + * If the current {@code Observable} signals an {@code onError}, the termination of the last inner {@code ObservableSource} will emit that error as is + * or wrapped into a {@link CompositeException} along with the other possible errors the former inner {@code ObservableSource}s signaled. *

- * + * *

*
Scheduler:
*
{@code switchMapDelayError} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the element type of the inner ObservableSources and the output + * @param the element type of the inner {@code ObservableSource}s and the output * @param mapper - * a function that, when applied to an item emitted by the source ObservableSource, returns an - * ObservableSource + * a function that, when applied to an item emitted by the current {@code Observable}, returns an + * {@code ObservableSource} * @param bufferSize - * the number of elements to prefetch from the current active inner ObservableSource - * @return an Observable that emits the items emitted by the ObservableSource returned from applying {@code func} to the most recently emitted item emitted by the source ObservableSource + * the number of elements expected from the current active inner {@code ObservableSource} to be buffered + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: FlatMap * @see #switchMap(Function, int) * @since 2.0 @@ -13059,7 +13720,7 @@ public final Observable switchMapDelayError(@NonNull Function Observable switchMapDelayError(@NonNull Function> mapper, int bufferSize) { + public final <@NonNull R> Observable switchMapDelayError(@NonNull Function> mapper, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); if (this instanceof ScalarSupplier) { @@ -13074,14 +13735,18 @@ public final Observable switchMapDelayError(@NonNull Function - * + * *

- * This method returns an ObservableSource that will invoke a subscribing {@link Observer}'s + * This method returns an {@code Observable} that will invoke a subscribing {@link Observer}'s * {@link Observer#onNext onNext} function a maximum of {@code count} times before invoking * {@link Observer#onComplete onComplete}. + *

+ * Taking {@code 0} items from the current {@code Observable} will still subscribe to it, allowing the + * subscription-time side-effects to happen there, but will be immediately disposed and the downstream completed + * without any item emission. *

*
Scheduler:
*
This version of {@code take} does not operate by default on a particular {@link Scheduler}.
@@ -13089,8 +13754,8 @@ public final Observable switchMapDelayError(@NonNull FunctionReactiveX operators documentation: Take */ @CheckReturnValue @@ -13104,23 +13769,24 @@ public final Observable take(long count) { } /** - * Returns an Observable that emits those items emitted by source ObservableSource before a specified time runs + * Returns an {@code Observable} that emits those items emitted by the current {@code Observable} before a specified time runs * out. *

* If time runs out before the {@code Observable} completes normally, the {@code onComplete} event will be * signaled on the default {@code computation} {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
This version of {@code take} operates by default on the {@code computation} {@link Scheduler}.
+ *
This version of {@code take} operates by default on the {@code computation} {@code Scheduler}.
*
* * @param time * the length of the time window * @param unit * the time unit of {@code time} - * @return an Observable that emits those items emitted by the source ObservableSource before the time runs out + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Take */ @CheckReturnValue @@ -13131,16 +13797,16 @@ public final Observable take(long time, @NonNull TimeUnit unit) { } /** - * Returns an Observable that emits those items emitted by source ObservableSource before a specified time (on a - * specified Scheduler) runs out. + * Returns an {@code Observable} that emits those items emitted by the current {@code Observable} before a specified time (on a + * specified {@link Scheduler}) runs out. *

* If time runs out before the {@code Observable} completes normally, the {@code onComplete} event will be - * signaled on the provided {@link Scheduler}. + * signaled on the provided {@code Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param time @@ -13148,9 +13814,9 @@ public final Observable take(long time, @NonNull TimeUnit unit) { * @param unit * the time unit of {@code time} * @param scheduler - * the Scheduler used for time source - * @return an Observable that emits those items emitted by the source ObservableSource before the time runs out, - * according to the specified Scheduler + * the {@code Scheduler} used for time source + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Take */ @CheckReturnValue @@ -13161,21 +13827,21 @@ public final Observable take(long time, @NonNull TimeUnit unit, @NonNull Sche } /** - * Returns an Observable that emits at most the last {@code count} items emitted by the source ObservableSource. If the source emits fewer than - * {@code count} items then all of its items are emitted. + * Returns an {@code Observable} that emits at most the last {@code count} items emitted by the current {@code Observable}. + * If the source emits fewer than {@code count} items then all of its items are emitted. *

- * + * *

*
Scheduler:
*
This version of {@code takeLast} does not operate by default on a particular {@link Scheduler}.
*
* * @param count - * the maximum number of items to emit from the end of the sequence of items emitted by the source - * ObservableSource - * @return an Observable that emits at most the last {@code count} items emitted by the source ObservableSource - * @throws IndexOutOfBoundsException - * if {@code count} is less than zero + * the maximum number of items to emit from the end of the sequence of items emitted by the current + * {@code Observable} + * @return the new {@code Observable} instance + * @throws IllegalArgumentException + * if {@code count} is negative * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -13183,7 +13849,7 @@ public final Observable take(long time, @NonNull TimeUnit unit, @NonNull Sche @NonNull public final Observable takeLast(int count) { if (count < 0) { - throw new IndexOutOfBoundsException("count >= 0 required but it was " + count); + throw new IllegalArgumentException("count >= 0 required but it was " + count); } if (count == 0) { return RxJavaPlugins.onAssembly(new ObservableIgnoreElements<>(this)); @@ -13195,14 +13861,14 @@ public final Observable takeLast(int count) { } /** - * Returns an Observable that emits at most a specified number of items from the source ObservableSource that were - * emitted in a specified window of time before the ObservableSource completed. + * Returns an {@code Observable} that emits at most a specified number of items from the current {@code Observable} that were + * emitted in a specified window of time before the current {@code Observable} completed. *

- * + * *

*
Scheduler:
*
{@code takeLast} does not operate on any particular scheduler but uses the current time - * from the {@code computation} {@link Scheduler}.
+ * from the {@code trampoline} {@link Scheduler}. *
* * @param count @@ -13211,8 +13877,9 @@ public final Observable takeLast(int count) { * the length of the time window * @param unit * the time unit of {@code time} - * @return an Observable that emits at most {@code count} items from the source ObservableSource that were emitted - * in a specified window of time before the ObservableSource completed + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code count} is negative * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -13223,14 +13890,14 @@ public final Observable takeLast(long count, long time, @NonNull TimeUnit uni } /** - * Returns an Observable that emits at most a specified number of items from the source ObservableSource that were - * emitted in a specified window of time before the ObservableSource completed, where the timing information is - * provided by a given Scheduler. + * Returns an {@code Observable} that emits at most a specified number of items from the current {@code Observable} that were + * emitted in a specified window of time before the current {@code Observable} completed, where the timing information is + * provided by a given {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use for tracking the current time
+ *
You specify which {@code Scheduler} this operator will use for tracking the current time
*
* * @param count @@ -13240,12 +13907,11 @@ public final Observable takeLast(long count, long time, @NonNull TimeUnit uni * @param unit * the time unit of {@code time} * @param scheduler - * the {@link Scheduler} that provides the timestamps for the observed items - * @return an Observable that emits at most {@code count} items from the source ObservableSource that were emitted - * in a specified window of time before the ObservableSource completed, where the timing information is - * provided by the given {@code scheduler} - * @throws IndexOutOfBoundsException - * if {@code count} is less than zero + * the {@code Scheduler} that provides the timestamps for the observed items + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException + * if {@code count} is negative * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -13256,14 +13922,14 @@ public final Observable takeLast(long count, long time, @NonNull TimeUnit uni } /** - * Returns an Observable that emits at most a specified number of items from the source ObservableSource that were - * emitted in a specified window of time before the ObservableSource completed, where the timing information is - * provided by a given Scheduler. + * Returns an {@code Observable} that emits at most a specified number of items from the current {@code Observable} that were + * emitted in a specified window of time before the current {@code Observable} completed, where the timing information is + * provided by a given {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use for tracking the current time
+ *
You specify which {@code Scheduler} this operator will use for tracking the current time
*
* * @param count @@ -13273,17 +13939,16 @@ public final Observable takeLast(long count, long time, @NonNull TimeUnit uni * @param unit * the time unit of {@code time} * @param scheduler - * the {@link Scheduler} that provides the timestamps for the observed items + * the {@code Scheduler} that provides the timestamps for the observed items * @param delayError - * if true, an exception signalled by the current Observable is delayed until the regular elements are consumed - * by the downstream; if false, an exception is immediately signalled and all regular elements dropped + * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed + * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped * @param bufferSize * the hint about how many elements to expect to be last - * @return an Observable that emits at most {@code count} items from the source ObservableSource that were emitted - * in a specified window of time before the ObservableSource completed, where the timing information is - * provided by the given {@code scheduler} - * @throws IndexOutOfBoundsException - * if {@code count} is less than zero + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException + * if {@code count} is negative or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -13294,27 +13959,28 @@ public final Observable takeLast(long count, long time, @NonNull TimeUnit uni Objects.requireNonNull(scheduler, "scheduler is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); if (count < 0) { - throw new IndexOutOfBoundsException("count >= 0 required but it was " + count); + throw new IllegalArgumentException("count >= 0 required but it was " + count); } return RxJavaPlugins.onAssembly(new ObservableTakeLastTimed<>(this, count, time, unit, scheduler, bufferSize, delayError)); } /** - * Returns an Observable that emits the items from the source ObservableSource that were emitted in a specified - * window of time before the ObservableSource completed. + * Returns an {@code Observable} that emits the items from the current {@code Observable} that were emitted in a specified + * window of time before the current {@code Observable} completed. *

- * + * *

*
Scheduler:
- *
This version of {@code takeLast} operates by default on the {@code computation} {@link Scheduler}.
+ *
{@code takeLast} does not operate on any particular scheduler but uses the current time + * from the {@code trampoline} {@link Scheduler}.
*
* * @param time * the length of the time window * @param unit * the time unit of {@code time} - * @return an Observable that emits the items from the source ObservableSource that were emitted in the window of - * time before the ObservableSource completed specified by {@code time} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -13325,13 +13991,14 @@ public final Observable takeLast(long time, @NonNull TimeUnit unit) { } /** - * Returns an Observable that emits the items from the source ObservableSource that were emitted in a specified - * window of time before the ObservableSource completed. + * Returns an {@code Observable} that emits the items from the current {@code Observable} that were emitted in a specified + * window of time before the current {@code Observable} completed. *

- * + * *

*
Scheduler:
- *
This version of {@code takeLast} operates by default on the {@code computation} {@link Scheduler}.
+ *
{@code takeLast} does not operate on any particular scheduler but uses the current time + * from the {@code trampoline} {@link Scheduler}.
*
* * @param time @@ -13339,10 +14006,11 @@ public final Observable takeLast(long time, @NonNull TimeUnit unit) { * @param unit * the time unit of {@code time} * @param delayError - * if true, an exception signalled by the current Observable is delayed until the regular elements are consumed - * by the downstream; if false, an exception is immediately signalled and all regular elements dropped - * @return an Observable that emits the items from the source ObservableSource that were emitted in the window of - * time before the ObservableSource completed specified by {@code time} + * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed + * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -13353,14 +14021,14 @@ public final Observable takeLast(long time, @NonNull TimeUnit unit, boolean d } /** - * Returns an Observable that emits the items from the source ObservableSource that were emitted in a specified - * window of time before the ObservableSource completed, where the timing information is provided by a specified - * Scheduler. + * Returns an {@code Observable} that emits the items from the current {@code Observable} that were emitted in a specified + * window of time before the current {@code Observable} completed, where the timing information is provided by a specified + * {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param time @@ -13368,10 +14036,9 @@ public final Observable takeLast(long time, @NonNull TimeUnit unit, boolean d * @param unit * the time unit of {@code time} * @param scheduler - * the Scheduler that provides the timestamps for the Observed items - * @return an Observable that emits the items from the source ObservableSource that were emitted in the window of - * time before the ObservableSource completed specified by {@code time}, where the timing information is - * provided by {@code scheduler} + * the {@code Scheduler} that provides the timestamps for the observed items + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -13382,14 +14049,14 @@ public final Observable takeLast(long time, @NonNull TimeUnit unit, @NonNull } /** - * Returns an Observable that emits the items from the source ObservableSource that were emitted in a specified - * window of time before the ObservableSource completed, where the timing information is provided by a specified - * Scheduler. + * Returns an {@code Observable} that emits the items from the current {@code Observable} that were emitted in a specified + * window of time before the current {@code Observable} completed, where the timing information is provided by a specified + * {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param time @@ -13397,13 +14064,12 @@ public final Observable takeLast(long time, @NonNull TimeUnit unit, @NonNull * @param unit * the time unit of {@code time} * @param scheduler - * the Scheduler that provides the timestamps for the Observed items + * the {@code Scheduler} that provides the timestamps for the observed items * @param delayError - * if true, an exception signalled by the current Observable is delayed until the regular elements are consumed - * by the downstream; if false, an exception is immediately signalled and all regular elements dropped - * @return an Observable that emits the items from the source ObservableSource that were emitted in the window of - * time before the ObservableSource completed specified by {@code time}, where the timing information is - * provided by {@code scheduler} + * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed + * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -13414,14 +14080,14 @@ public final Observable takeLast(long time, @NonNull TimeUnit unit, @NonNull } /** - * Returns an Observable that emits the items from the source ObservableSource that were emitted in a specified - * window of time before the ObservableSource completed, where the timing information is provided by a specified - * Scheduler. + * Returns an {@code Observable} that emits the items from the current {@code Observable} that were emitted in a specified + * window of time before the current {@code Observable} completed, where the timing information is provided by a specified + * {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param time @@ -13429,15 +14095,15 @@ public final Observable takeLast(long time, @NonNull TimeUnit unit, @NonNull * @param unit * the time unit of {@code time} * @param scheduler - * the Scheduler that provides the timestamps for the Observed items + * the {@code Scheduler} that provides the timestamps for the observed items * @param delayError - * if true, an exception signalled by the current Observable is delayed until the regular elements are consumed - * by the downstream; if false, an exception is immediately signalled and all regular elements dropped + * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed + * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped * @param bufferSize * the hint about how many elements to expect to be last - * @return an Observable that emits the items from the source ObservableSource that were emitted in the window of - * time before the ObservableSource completed specified by {@code time}, where the timing information is - * provided by {@code scheduler} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: TakeLast */ @CheckReturnValue @@ -13448,36 +14114,37 @@ public final Observable takeLast(long time, @NonNull TimeUnit unit, @NonNull } /** - * Returns an Observable that emits the items emitted by the source Observable until a second ObservableSource - * emits an item. + * Returns an {@code Observable} that emits the items emitted by the current {@code Observable} until a second {@link ObservableSource} + * emits an item or completes. *

- * + * *

*
Scheduler:
*
{@code takeUntil} does not operate by default on a particular {@link Scheduler}.
*
* * @param other - * the ObservableSource whose first emitted item will cause {@code takeUntil} to stop emitting items - * from the source Observable + * the {@code ObservableSource} whose first emitted item or completion will cause {@code takeUntil} to stop emitting items + * from the current {@code Observable} * @param * the type of items emitted by {@code other} - * @return an Observable that emits the items emitted by the source Observable until such time as {@code other} emits its first item + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: TakeUntil */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable takeUntil(@NonNull ObservableSource other) { + public final <@NonNull U> Observable takeUntil(@NonNull ObservableSource other) { Objects.requireNonNull(other, "other is null"); return RxJavaPlugins.onAssembly(new ObservableTakeUntil<>(this, other)); } /** - * Returns an Observable that emits items emitted by the source Observable, checks the specified predicate + * Returns an {@code Observable} that emits items emitted by the current {@code Observable}, checks the specified predicate * for each item, and then completes when the condition is satisfied. *

- * + * *

* The difference between this operator and {@link #takeWhile(Predicate)} is that here, the condition is * evaluated after the item is emitted. @@ -13488,9 +14155,9 @@ public final Observable takeUntil(@NonNull ObservableSource other) { *

* * @param stopPredicate - * a function that evaluates an item emitted by the source Observable and returns a Boolean - * @return an Observable that first emits items emitted by the source Observable, checks the specified - * condition after each item, and then completes when the condition is satisfied. + * a function that evaluates an item emitted by the current {@code Observable} and returns a {@link Boolean} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code stopPredicate} is {@code null} * @see ReactiveX operators documentation: TakeUntil * @see Observable#takeWhile(Predicate) * @since 1.1.0 @@ -13504,19 +14171,19 @@ public final Observable takeUntil(@NonNull Predicate stopPredicate } /** - * Returns an Observable that emits items emitted by the source ObservableSource so long as each item satisfied a + * Returns an {@code Observable} that emits items emitted by the current {@code Observable} so long as each item satisfied a * specified condition, and then completes as soon as this condition is not satisfied. *

- * + * *

*
Scheduler:
*
{@code takeWhile} does not operate by default on a particular {@link Scheduler}.
*
* * @param predicate - * a function that evaluates an item emitted by the source ObservableSource and returns a Boolean - * @return an Observable that emits the items from the source ObservableSource so long as each item satisfies the - * condition defined by {@code predicate}, then completes + * a function that evaluates an item emitted by the current {@code Observable} and returns a {@link Boolean} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @see ReactiveX operators documentation: TakeWhile * @see Observable#takeUntil(Predicate) */ @@ -13529,13 +14196,13 @@ public final Observable takeWhile(@NonNull Predicate predicate) { } /** - * Returns an Observable that emits only the first item emitted by the source ObservableSource during sequential + * Returns an {@code Observable} that emits only the first item emitted by the current {@code Observable} during sequential * time windows of a specified duration. *

* This differs from {@link #throttleLast} in that this only tracks passage of time whereas - * {@link #throttleLast} ticks at scheduled intervals. + * {@code throttleLast} ticks at scheduled intervals. *

- * + * *

*
Scheduler:
*
{@code throttleFirst} operates by default on the {@code computation} {@link Scheduler}.
@@ -13545,7 +14212,8 @@ public final Observable takeWhile(@NonNull Predicate predicate) { * time to wait before emitting another item after emitting the last item * @param unit * the unit of time of {@code windowDuration} - * @return an Observable that performs the throttle operation + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Sample */ @CheckReturnValue @@ -13556,16 +14224,16 @@ public final Observable throttleFirst(long windowDuration, @NonNull TimeUnit } /** - * Returns an Observable that emits only the first item emitted by the source ObservableSource during sequential - * time windows of a specified duration, where the windows are managed by a specified Scheduler. + * Returns an {@code Observable} that emits only the first item emitted by the current {@code Observable} during sequential + * time windows of a specified duration, where the windows are managed by a specified {@link Scheduler}. *

* This differs from {@link #throttleLast} in that this only tracks passage of time whereas - * {@link #throttleLast} ticks at scheduled intervals. + * {@code throttleLast} ticks at scheduled intervals. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param skipDuration @@ -13573,9 +14241,10 @@ public final Observable throttleFirst(long windowDuration, @NonNull TimeUnit * @param unit * the unit of time of {@code skipDuration} * @param scheduler - * the {@link Scheduler} to use internally to manage the timers that handle timeout for each + * the {@code Scheduler} to use internally to manage the timers that handle timeout for each * event - * @return an Observable that performs the throttle operation + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Sample */ @CheckReturnValue @@ -13584,28 +14253,68 @@ public final Observable throttleFirst(long windowDuration, @NonNull TimeUnit public final Observable throttleFirst(long skipDuration, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new ObservableThrottleFirstTimed<>(this, skipDuration, unit, scheduler)); + return RxJavaPlugins.onAssembly(new ObservableThrottleFirstTimed<>(this, skipDuration, unit, scheduler, null)); + } + + /** + * Returns an {@code Observable} that emits only the first item emitted by the current {@code Observable} during sequential + * time windows of a specified duration, where the windows are managed by a specified {@link Scheduler}. + *

+ * This differs from {@link #throttleLast} in that this only tracks passage of time whereas + * {@code throttleLast} ticks at scheduled intervals. + *

+ * + *

+ *
Scheduler:
+ *
You specify which {@code Scheduler} this operator will use.
+ *
+ * + * @param skipDuration + * time to wait before emitting another item after emitting the last item + * @param unit + * the unit of time of {@code skipDuration} + * @param scheduler + * the {@code Scheduler} to use internally to manage the timers that handle timeout for each + * event + * @param onDropped + * called when an item doesn't get delivered to the downstream + * + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} or {@code onDropped} is {@code null} + * @see ReactiveX operators documentation: Sample + * @since 3.1.6 - Experimental + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.CUSTOM) + @NonNull + @Experimental + public final Observable throttleFirst(long skipDuration, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + Objects.requireNonNull(onDropped, "onDropped is null"); + return RxJavaPlugins.onAssembly(new ObservableThrottleFirstTimed<>(this, skipDuration, unit, scheduler, onDropped)); } /** - * Returns an Observable that emits only the last item emitted by the source ObservableSource during sequential + * Returns an {@code Observable} that emits only the last item emitted by the current {@code Observable} during sequential * time windows of a specified duration. *

* This differs from {@link #throttleFirst} in that this ticks along at a scheduled interval whereas - * {@link #throttleFirst} does not tick, it just tracks passage of time. + * {@code throttleFirst} does not tick, it just tracks passage of time. *

- * + * *

*
Scheduler:
*
{@code throttleLast} operates by default on the {@code computation} {@link Scheduler}.
*
* * @param intervalDuration - * duration of windows within which the last item emitted by the source ObservableSource will be + * duration of windows within which the last item emitted by the current {@code Observable} will be * emitted * @param unit * the unit of time of {@code intervalDuration} - * @return an Observable that performs the throttle operation + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Sample * @see #sample(long, TimeUnit) */ @@ -13617,27 +14326,65 @@ public final Observable throttleLast(long intervalDuration, @NonNull TimeUnit } /** - * Returns an Observable that emits only the last item emitted by the source ObservableSource during sequential - * time windows of a specified duration, where the duration is governed by a specified Scheduler. + * Returns an {@code Observable} that emits only the last item emitted by the current {@code Observable} during sequential + * time windows of a specified duration, where the duration is governed by a specified {@link Scheduler}. *

* This differs from {@link #throttleFirst} in that this ticks along at a scheduled interval whereas - * {@link #throttleFirst} does not tick, it just tracks passage of time. + * {@code throttleFirst} does not tick, it just tracks passage of time. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
+ *
+ * + * @param intervalDuration + * duration of windows within which the last item emitted by the current {@code Observable} will be + * emitted + * @param unit + * the unit of time of {@code intervalDuration} + * @param scheduler + * the {@code Scheduler} to use internally to manage the timers that handle timeout for each + * event + * @param onDropped + * called with the current entry when it has been replaced by a new one + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} or {@code onDropped} is {@code null} + * @see ReactiveX operators documentation: Sample + * @see #sample(long, TimeUnit, Scheduler) + * @since 3.1.6 - Experimental + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.CUSTOM) + @NonNull + @Experimental + public final Observable throttleLast(long intervalDuration, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { + return sample(intervalDuration, unit, scheduler, false, onDropped); + } + + /** + * Returns an {@code Observable} that emits only the last item emitted by the current {@code Observable} during sequential + * time windows of a specified duration, where the duration is governed by a specified {@link Scheduler}. + *

+ * This differs from {@link #throttleFirst} in that this ticks along at a scheduled interval whereas + * {@code throttleFirst} does not tick, it just tracks passage of time. + *

+ * + *

+ *
Scheduler:
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param intervalDuration - * duration of windows within which the last item emitted by the source ObservableSource will be + * duration of windows within which the last item emitted by the current {@code Observable} will be * emitted * @param unit * the unit of time of {@code intervalDuration} * @param scheduler - * the {@link Scheduler} to use internally to manage the timers that handle timeout for each + * the {@code Scheduler} to use internally to manage the timers that handle timeout for each * event - * @return an Observable that performs the throttle operation + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Sample * @see #sample(long, TimeUnit, Scheduler) */ @@ -13649,11 +14396,11 @@ public final Observable throttleLast(long intervalDuration, @NonNull TimeUnit } /** - * Throttles items from the upstream {@code Observable} by first emitting the next + * Throttles items from the current {@code Observable} by first emitting the next * item from upstream, then periodically emitting the latest item (if any) when * the specified timeout elapses between them. *

- * + * *

* Unlike the option with {@link #throttleLatest(long, TimeUnit, boolean)}, the very last item being held back * (if any) is not emitted when the upstream completes. @@ -13668,7 +14415,8 @@ public final Observable throttleLast(long intervalDuration, @NonNull TimeUnit * @param timeout the time to wait after an item emission towards the downstream * before trying to emit the latest item from upstream again * @param unit the time unit - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see #throttleLatest(long, TimeUnit, boolean) * @see #throttleLatest(long, TimeUnit, Scheduler) * @since 2.2 @@ -13681,11 +14429,11 @@ public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit) } /** - * Throttles items from the upstream {@code Observable} by first emitting the next + * Throttles items from the current {@code Observable} by first emitting the next * item from upstream, then periodically emitting the latest item (if any) when * the specified timeout elapses between them. *

- * + * *

* If no items were emitted from the upstream during this timeout phase, the next * upstream item is emitted immediately and the timeout window starts from then. @@ -13701,7 +14449,8 @@ public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit) * immediately when the upstream completes, regardless if there is * a timeout window active or not. If {@code false}, the very last * upstream item is ignored and the flow terminates. - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see #throttleLatest(long, TimeUnit, Scheduler, boolean) * @since 2.2 */ @@ -13713,11 +14462,11 @@ public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, } /** - * Throttles items from the upstream {@code Observable} by first emitting the next + * Throttles items from the current {@code Observable} by first emitting the next * item from upstream, then periodically emitting the latest item (if any) when * the specified timeout elapses between them. *

- * + * *

* Unlike the option with {@link #throttleLatest(long, TimeUnit, Scheduler, boolean)}, the very last item being held back * (if any) is not emitted when the upstream completes. @@ -13732,9 +14481,10 @@ public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, * @param timeout the time to wait after an item emission towards the downstream * before trying to emit the latest item from upstream again * @param unit the time unit - * @param scheduler the {@link Scheduler} where the timed wait and latest item + * @param scheduler the {@code Scheduler} where the timed wait and latest item * emission will be performed - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see #throttleLatest(long, TimeUnit, Scheduler, boolean) * @since 2.2 */ @@ -13746,11 +14496,11 @@ public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, } /** - * Throttles items from the upstream {@code Observable} by first emitting the next + * Throttles items from the current {@code Observable} by first emitting the next * item from upstream, then periodically emitting the latest item (if any) when * the specified timeout elapses between them. *

- * + * *

* If no items were emitted from the upstream during this timeout phase, the next * upstream item is emitted immediately and the timeout window starts from then. @@ -13762,13 +14512,14 @@ public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, * @param timeout the time to wait after an item emission towards the downstream * before trying to emit the latest item from upstream again * @param unit the time unit - * @param scheduler the {@link Scheduler} where the timed wait and latest item + * @param scheduler the {@code Scheduler} where the timed wait and latest item * emission will be performed * @param emitLast If {@code true}, the very last item from the upstream will be emitted * immediately when the upstream completes, regardless if there is * a timeout window active or not. If {@code false}, the very last * upstream item is ignored and the flow terminates. - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -13777,31 +14528,79 @@ public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new ObservableThrottleLatest<>(this, timeout, unit, scheduler, emitLast)); + return RxJavaPlugins.onAssembly(new ObservableThrottleLatest<>(this, timeout, unit, scheduler, emitLast, null)); } /** - * Returns an Observable that mirrors the source ObservableSource, except that it drops items emitted by the - * source ObservableSource that are followed by newer items before a timeout value expires. The timer resets on + * Throttles items from the current {@code Observable} by first emitting the next + * item from upstream, then periodically emitting the latest item (if any) when + * the specified timeout elapses between them, invoking the consumer for any dropped item. + *

+ * + *

+ * If no items were emitted from the upstream during this timeout phase, the next + * upstream item is emitted immediately and the timeout window starts from then. + *

+ *
Scheduler:
+ *
You specify which {@link Scheduler} this operator will use.
+ *
Error handling:
+ *
+ * If the upstream signals an {@code onError} or {@code onDropped} callback crashes, + * the error is delivered immediately to the downstream. If both happen, a {@link CompositeException} + * is created, containing both the upstream and the callback error. + * If the {@code onDropped} callback crashes when the sequence gets disposed, the exception is forwarded + * to the global error handler via {@link RxJavaPlugins#onError(Throwable)}. + *
+ *
+ * @param timeout the time to wait after an item emission towards the downstream + * before trying to emit the latest item from upstream again + * @param unit the time unit + * @param scheduler the {@code Scheduler} where the timed wait and latest item + * emission will be performed + * @param emitLast If {@code true}, the very last item from the upstream will be emitted + * immediately when the upstream completes, regardless if there is + * a timeout window active or not. If {@code false}, the very last + * upstream item is ignored and the flow terminates. + * @param onDropped called when an item is replaced by a newer item that doesn't get delivered + * to the downstream, including the very last item if {@code emitLast} is {@code false} + * and the current undelivered item when the sequence gets disposed. + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code onDropped} is {@code null} + * @since 3.1.6 - Experimental + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.CUSTOM) + @NonNull + @Experimental + public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast, @NonNull Consumer onDropped) { + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + Objects.requireNonNull(onDropped, "onDropped is null"); + return RxJavaPlugins.onAssembly(new ObservableThrottleLatest<>(this, timeout, unit, scheduler, emitLast, onDropped)); + } + + /** + * Returns an {@code Observable} that mirrors the current {@code Observable}, except that it drops items emitted by the + * current {@code Observable} that are followed by newer items before a timeout value expires. The timer resets on * each emission (alias to {@link #debounce(long, TimeUnit, Scheduler)}). *

- * Note: If items keep being emitted by the source ObservableSource faster than the timeout then no items - * will be emitted by the resulting ObservableSource. + * Note: If items keep being emitted by the current {@code Observable} faster than the timeout then no items + * will be emitted by the resulting {@code Observable}. *

- * + * *

*
Scheduler:
*
{@code throttleWithTimeout} operates by default on the {@code computation} {@link Scheduler}.
*
* * @param timeout - * the length of the window of time that must pass after the emission of an item from the source - * ObservableSource in which that ObservableSource emits no items in order for the item to be emitted by the - * resulting ObservableSource + * the length of the window of time that must pass after the emission of an item from the current + * {@code Observable}, in which the current {@code Observable} emits no items, in order for the item to be emitted by the + * resulting {@code Observable} * @param unit * the unit of time for the specified {@code timeout} - * @return an Observable that filters out items from the source ObservableSource that are too quickly followed by - * newer items + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Debounce * @see #debounce(long, TimeUnit) */ @@ -13813,30 +14612,30 @@ public final Observable throttleWithTimeout(long timeout, @NonNull TimeUnit u } /** - * Returns an Observable that mirrors the source ObservableSource, except that it drops items emitted by the - * source ObservableSource that are followed by newer items before a timeout value expires on a specified - * Scheduler. The timer resets on each emission (Alias to {@link #debounce(long, TimeUnit, Scheduler)}). + * Returns an {@code Observable} that mirrors the current {@code Observable}, except that it drops items emitted by the + * current {@code Observable} that are followed by newer items before a timeout value expires on a specified + * {@link Scheduler}. The timer resets on each emission (Alias to {@link #debounce(long, TimeUnit, Scheduler)}). *

- * Note: If items keep being emitted by the source ObservableSource faster than the timeout then no items - * will be emitted by the resulting ObservableSource. + * Note: If items keep being emitted by the current {@code Observable} faster than the timeout then no items + * will be emitted by the resulting {@code Observable}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param timeout - * the length of the window of time that must pass after the emission of an item from the source - * ObservableSource in which that ObservableSource emits no items in order for the item to be emitted by the - * resulting ObservableSource + * the length of the window of time that must pass after the emission of an item from the current + * {@code Observable}, in which the current {@code Observable} emits no items, in order for the item to be emitted by the + * resulting {@code Observable} * @param unit * the unit of time for the specified {@code timeout} * @param scheduler - * the {@link Scheduler} to use internally to manage the timers that handle the timeout for each + * the {@code Scheduler} to use internally to manage the timers that handle the timeout for each * item - * @return an Observable that filters out items from the source ObservableSource that are too quickly followed by - * newer items + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Debounce * @see #debounce(long, TimeUnit, Scheduler) */ @@ -13848,17 +14647,56 @@ public final Observable throttleWithTimeout(long timeout, @NonNull TimeUnit u } /** - * Returns an Observable that emits records of the time interval between consecutive items emitted by the - * source ObservableSource. + * Returns an {@code Observable} that mirrors the current {@code Observable}, except that it drops items emitted by the + * current {@code Observable} that are followed by newer items before a timeout value expires on a specified + * {@link Scheduler}. The timer resets on each emission (Alias to {@link #debounce(long, TimeUnit, Scheduler)}). *

- * + * Note: If items keep being emitted by the current {@code Observable} faster than the timeout then no items + * will be emitted by the resulting {@code Observable}. + *

+ * + *

+ *
Scheduler:
+ *
You specify which {@code Scheduler} this operator will use.
+ *
+ * + * @param timeout + * the length of the window of time that must pass after the emission of an item from the current + * {@code Observable}, in which the current {@code Observable} emits no items, in order for the item to be emitted by the + * resulting {@code Observable} + * @param unit + * the unit of time for the specified {@code timeout} + * @param scheduler + * the {@code Scheduler} to use internally to manage the timers that handle the timeout for each + * item + * @param onDropped + * called with the current entry when it has been replaced by a new one + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} or {@code onDropped} is {@code null} + * @see ReactiveX operators documentation: Debounce + * @see #debounce(long, TimeUnit, Scheduler, Consumer) + * @since 3.1.6 - Experimental + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.CUSTOM) + @NonNull + @Experimental + public final Observable throttleWithTimeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { + return debounce(timeout, unit, scheduler, onDropped); + } + + /** + * Returns an {@code Observable} that emits records of the time interval between consecutive items emitted by the + * current {@code Observable}. + *

+ * *

*
Scheduler:
*
{@code timeInterval} does not operate on any particular scheduler but uses the current time * from the {@code computation} {@link Scheduler}.
*
* - * @return an Observable that emits time interval information items + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: TimeInterval */ @CheckReturnValue @@ -13869,19 +14707,20 @@ public final Observable> timeInterval() { } /** - * Returns an Observable that emits records of the time interval between consecutive items emitted by the - * source ObservableSource, where this interval is computed on a specified Scheduler. + * Returns an {@code Observable} that emits records of the time interval between consecutive items emitted by the + * current {@code Observable}, where this interval is computed on a specified {@link Scheduler}. *

- * + * *

*
Scheduler:
*
The operator does not operate on any particular scheduler but uses the current time - * from the specified {@link Scheduler}.
+ * from the specified {@code Scheduler}. *
* * @param scheduler - * the {@link Scheduler} used to compute time intervals - * @return an Observable that emits time interval information items + * the {@code Scheduler} used to compute time intervals + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: TimeInterval */ @CheckReturnValue @@ -13892,10 +14731,10 @@ public final Observable> timeInterval(@NonNull Scheduler scheduler) { } /** - * Returns an Observable that emits records of the time interval between consecutive items emitted by the - * source ObservableSource. + * Returns an {@code Observable} that emits records of the time interval between consecutive items emitted by the + * current {@code Observable}. *

- * + * *

*
Scheduler:
*
{@code timeInterval} does not operate on any particular scheduler but uses the current time @@ -13903,7 +14742,8 @@ public final Observable> timeInterval(@NonNull Scheduler scheduler) { *
* * @param unit the time unit for the current time - * @return an Observable that emits time interval information items + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: TimeInterval */ @CheckReturnValue @@ -13914,20 +14754,21 @@ public final Observable> timeInterval(@NonNull TimeUnit unit) { } /** - * Returns an Observable that emits records of the time interval between consecutive items emitted by the - * source ObservableSource, where this interval is computed on a specified Scheduler. + * Returns an {@code Observable} that emits records of the time interval between consecutive items emitted by the + * current {@code Observable}, where this interval is computed on a specified {@link Scheduler}. *

- * + * *

*
Scheduler:
*
The operator does not operate on any particular scheduler but uses the current time - * from the specified {@link Scheduler}.
+ * from the specified {@code Scheduler}. *
* * @param unit the time unit for the current time * @param scheduler - * the {@link Scheduler} used to compute time intervals - * @return an Observable that emits time interval information items + * the {@code Scheduler} used to compute time intervals + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: TimeInterval */ @CheckReturnValue @@ -13940,12 +14781,12 @@ public final Observable> timeInterval(@NonNull TimeUnit unit, @NonNull } /** - * Returns an Observable that mirrors the source ObservableSource, but notifies observers of a - * {@code TimeoutException} if an item emitted by the source ObservableSource doesn't arrive within a window of - * time after the emission of the previous item, where that period of time is measured by an ObservableSource that + * Returns an {@code Observable} that mirrors the current {@code Observable}, but notifies observers of a + * {@link TimeoutException} if an item emitted by the current {@code Observable} doesn't arrive within a window of + * time after the emission of the previous item, where that period of time is measured by an {@link ObservableSource} that * is a function of the previous item. *

- * + * *

* Note: The arrival of the first source item is never timed out. *

@@ -13956,27 +14797,26 @@ public final Observable> timeInterval(@NonNull TimeUnit unit, @NonNull * @param * the timeout value type (ignored) * @param itemTimeoutIndicator - * a function that returns an ObservableSource for each item emitted by the source - * ObservableSource and that determines the timeout window for the subsequent item - * @return an Observable that mirrors the source ObservableSource, but notifies observers of a - * {@code TimeoutException} if an item emitted by the source ObservableSource takes longer to arrive than - * the time window defined by the selector for the previously emitted item + * a function that returns an {@code ObservableSource} for each item emitted by the current + * {@code Observable} and that determines the timeout window for the subsequent item + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code itemTimeoutIndicator} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable timeout(@NonNull Function> itemTimeoutIndicator) { + public final <@NonNull V> Observable timeout(@NonNull Function> itemTimeoutIndicator) { return timeout0(null, itemTimeoutIndicator, null); } /** - * Returns an Observable that mirrors the source ObservableSource, but that switches to a fallback ObservableSource if - * an item emitted by the source ObservableSource doesn't arrive within a window of time after the emission of the - * previous item, where that period of time is measured by an ObservableSource that is a function of the previous + * Returns an {@code Observable} that mirrors the current {@code Observable}, but that switches to a fallback {@link ObservableSource} if + * an item emitted by the current {@code Observable} doesn't arrive within a window of time after the emission of the + * previous item, where that period of time is measured by an {@code ObservableSource} that is a function of the previous * item. *

- * + * *

* Note: The arrival of the first source item is never timed out. *

@@ -13987,30 +14827,29 @@ public final Observable timeout(@NonNull Function * the timeout value type (ignored) * @param itemTimeoutIndicator - * a function that returns an ObservableSource, for each item emitted by the source ObservableSource, that + * a function that returns an {@code ObservableSource}, for each item emitted by the current {@code Observable}, that * determines the timeout window for the subsequent item - * @param other - * the fallback ObservableSource to switch to if the source ObservableSource times out - * @return an Observable that mirrors the source ObservableSource, but switches to mirroring a fallback ObservableSource - * if an item emitted by the source ObservableSource takes longer to arrive than the time window defined - * by the selector for the previously emitted item + * @param fallback + * the fallback {@code ObservableSource} to switch to if the current {@code Observable} times out + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code itemTimeoutIndicator} or {@code fallback} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable timeout(@NonNull Function> itemTimeoutIndicator, - @NonNull ObservableSource other) { - Objects.requireNonNull(other, "other is null"); - return timeout0(null, itemTimeoutIndicator, other); + public final <@NonNull V> Observable timeout(@NonNull Function> itemTimeoutIndicator, + @NonNull ObservableSource fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return timeout0(null, itemTimeoutIndicator, fallback); } /** - * Returns an Observable that mirrors the source ObservableSource but applies a timeout policy for each emitted + * Returns an {@code Observable} that mirrors the current {@code Observable} but applies a timeout policy for each emitted * item. If the next item isn't emitted within the specified timeout duration starting from its predecessor, - * the resulting ObservableSource terminates and notifies observers of a {@code TimeoutException}. + * the resulting {@code Observable} terminates and notifies observers of a {@link TimeoutException}. *

- * + * *

*
Scheduler:
*
This version of {@code timeout} operates by default on the {@code computation} {@link Scheduler}.
@@ -14018,26 +14857,26 @@ public final Observable timeout(@NonNull FunctionReactiveX operators documentation: Timeout */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Observable timeout(long timeout, @NonNull TimeUnit timeUnit) { - return timeout0(timeout, timeUnit, null, Schedulers.computation()); + public final Observable timeout(long timeout, @NonNull TimeUnit unit) { + return timeout0(timeout, unit, null, Schedulers.computation()); } /** - * Returns an Observable that mirrors the source ObservableSource but applies a timeout policy for each emitted + * Returns an {@code Observable} that mirrors the current {@code Observable} but applies a timeout policy for each emitted * item. If the next item isn't emitted within the specified timeout duration starting from its predecessor, - * the source ObservableSource is disposed and resulting ObservableSource begins instead - * to mirror a fallback ObservableSource. + * the current {@code Observable} is disposed and the resulting {@code Observable} begins instead + * to mirror a fallback {@link ObservableSource}. *

- * + * *

*
Scheduler:
*
This version of {@code timeout} operates by default on the {@code computation} {@link Scheduler}.
@@ -14045,88 +14884,89 @@ public final Observable timeout(long timeout, @NonNull TimeUnit timeUnit) { * * @param timeout * maximum duration between items before a timeout occurs - * @param timeUnit + * @param unit * the unit of time that applies to the {@code timeout} argument - * @param other - * the fallback ObservableSource to use in case of a timeout - * @return the source ObservableSource modified to switch to the fallback ObservableSource in case of a timeout + * @param fallback + * the fallback {@code ObservableSource} to use in case of a timeout + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code fallback} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Observable timeout(long timeout, @NonNull TimeUnit timeUnit, @NonNull ObservableSource other) { - Objects.requireNonNull(other, "other is null"); - return timeout0(timeout, timeUnit, other, Schedulers.computation()); + public final Observable timeout(long timeout, @NonNull TimeUnit unit, @NonNull ObservableSource fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return timeout0(timeout, unit, fallback, Schedulers.computation()); } /** - * Returns an Observable that mirrors the source ObservableSource but applies a timeout policy for each emitted - * item using a specified Scheduler. If the next item isn't emitted within the specified timeout duration - * starting from its predecessor, the source ObservableSource is disposed and resulting ObservableSource - * begins instead to mirror a fallback ObservableSource. + * Returns an {@code Observable} that mirrors the current {@code Observable} but applies a timeout policy for each emitted + * item using a specified {@link Scheduler}. If the next item isn't emitted within the specified timeout duration + * starting from its predecessor, the current {@code Observable} is disposed and returned {@code Observable} + * begins instead to mirror a fallback {@link ObservableSource}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param timeout * maximum duration between items before a timeout occurs - * @param timeUnit + * @param unit * the unit of time that applies to the {@code timeout} argument * @param scheduler - * the {@link Scheduler} to run the timeout timers on - * @param other - * the ObservableSource to use as the fallback in case of a timeout - * @return the source ObservableSource modified so that it will switch to the fallback ObservableSource in case of a - * timeout + * the {@code Scheduler} to run the timeout timers on + * @param fallback + * the {@code ObservableSource} to use as the fallback in case of a timeout + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code fallback} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable timeout(long timeout, @NonNull TimeUnit timeUnit, @NonNull Scheduler scheduler, @NonNull ObservableSource other) { - Objects.requireNonNull(other, "other is null"); - return timeout0(timeout, timeUnit, other, scheduler); + public final Observable timeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull ObservableSource fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return timeout0(timeout, unit, fallback, scheduler); } /** - * Returns an Observable that mirrors the source ObservableSource but applies a timeout policy for each emitted - * item, where this policy is governed on a specified Scheduler. If the next item isn't emitted within the - * specified timeout duration starting from its predecessor, the resulting ObservableSource terminates and - * notifies observers of a {@code TimeoutException}. + * Returns an {@code Observable} that mirrors the current {@code Observable} but applies a timeout policy for each emitted + * item, where this policy is governed on a specified {@link Scheduler}. If the next item isn't emitted within the + * specified timeout duration starting from its predecessor, the resulting {@code Observable} terminates and + * notifies observers of a {@link TimeoutException}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param timeout * maximum duration between items before a timeout occurs - * @param timeUnit + * @param unit * the unit of time that applies to the {@code timeout} argument * @param scheduler - * the Scheduler to run the timeout timers on - * @return the source ObservableSource modified to notify observers of a {@code TimeoutException} in case of a - * timeout + * the {@code Scheduler} to run the timeout timers on + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable timeout(long timeout, @NonNull TimeUnit timeUnit, @NonNull Scheduler scheduler) { - return timeout0(timeout, timeUnit, null, scheduler); + public final Observable timeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + return timeout0(timeout, unit, null, scheduler); } /** - * Returns an Observable that mirrors the source ObservableSource, but notifies observers of a - * {@code TimeoutException} if either the first item emitted by the source ObservableSource or any subsequent item - * doesn't arrive within time windows defined by other ObservableSources. + * Returns an {@code Observable} that mirrors the current {@code Observable}, but notifies observers of a + * {@link TimeoutException} if either the first item emitted by the current {@code Observable} or any subsequent item + * doesn't arrive within time windows defined by indicator {@link ObservableSource}s. *

- * + * *

*
Scheduler:
*
This version of {@code timeout} operates by default on the {@code immediate} {@link Scheduler}.
@@ -14137,32 +14977,31 @@ public final Observable timeout(long timeout, @NonNull TimeUnit timeUnit, @No * @param * the subsequent timeout value type (ignored) * @param firstTimeoutIndicator - * a function that returns an ObservableSource that determines the timeout window for the first source + * a function that returns an {@code ObservableSource} that determines the timeout window for the first source * item * @param itemTimeoutIndicator - * a function that returns an ObservableSource for each item emitted by the source ObservableSource and that + * a function that returns an {@code ObservableSource} for each item emitted by the current {@code Observable} and that * determines the timeout window in which the subsequent source item must arrive in order to * continue the sequence - * @return an Observable that mirrors the source ObservableSource, but notifies observers of a - * {@code TimeoutException} if either the first item or any subsequent item doesn't arrive within - * the time windows specified by the timeout selectors + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code firstTimeoutIndicator} or {@code itemTimeoutIndicator} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable timeout(@NonNull ObservableSource firstTimeoutIndicator, + public final <@NonNull U, @NonNull V> Observable timeout(@NonNull ObservableSource firstTimeoutIndicator, @NonNull Function> itemTimeoutIndicator) { Objects.requireNonNull(firstTimeoutIndicator, "firstTimeoutIndicator is null"); return timeout0(firstTimeoutIndicator, itemTimeoutIndicator, null); } /** - * Returns an Observable that mirrors the source ObservableSource, but switches to a fallback ObservableSource if either - * the first item emitted by the source ObservableSource or any subsequent item doesn't arrive within time windows - * defined by other ObservableSources. + * Returns an {@code Observable} that mirrors the current {@code Observable}, but switches to a fallback {@link ObservableSource} if either + * the first item emitted by the current {@code Observable} or any subsequent item doesn't arrive within time windows + * defined by indicator {@code ObservableSource}s. *

- * + * *

*
Scheduler:
*
This version of {@code timeout} operates by default on the {@code immediate} {@link Scheduler}.
@@ -14173,64 +15012,61 @@ public final Observable timeout(@NonNull ObservableSource firstTime * @param * the subsequent timeout value type (ignored) * @param firstTimeoutIndicator - * a function that returns an ObservableSource which determines the timeout window for the first source + * a function that returns an {@code ObservableSource} which determines the timeout window for the first source * item * @param itemTimeoutIndicator - * a function that returns an ObservableSource for each item emitted by the source ObservableSource and that + * a function that returns an {@code ObservableSource} for each item emitted by the current {@code Observable} and that * determines the timeout window in which the subsequent source item must arrive in order to * continue the sequence - * @param other - * the fallback ObservableSource to switch to if the source ObservableSource times out - * @return an Observable that mirrors the source ObservableSource, but switches to the {@code other} ObservableSource if - * either the first item emitted by the source ObservableSource or any subsequent item doesn't arrive - * within time windows defined by the timeout selectors + * @param fallback + * the fallback {@code ObservableSource} to switch to if the current {@code Observable} times out + * @return the new {@code Observable} instance * @throws NullPointerException - * if {@code itemTimeoutIndicator} is null, or - * if {@code other} is null + * if {@code firstTimeoutIndicator}, {@code itemTimeoutIndicator} or {@code fallback} is {@code null} * @see ReactiveX operators documentation: Timeout */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable timeout( + public final <@NonNull U, @NonNull V> Observable timeout( @NonNull ObservableSource firstTimeoutIndicator, @NonNull Function> itemTimeoutIndicator, - @NonNull ObservableSource other) { + @NonNull ObservableSource fallback) { Objects.requireNonNull(firstTimeoutIndicator, "firstTimeoutIndicator is null"); - Objects.requireNonNull(other, "other is null"); - return timeout0(firstTimeoutIndicator, itemTimeoutIndicator, other); + Objects.requireNonNull(fallback, "fallback is null"); + return timeout0(firstTimeoutIndicator, itemTimeoutIndicator, fallback); } @NonNull - private Observable timeout0(long timeout, @NonNull TimeUnit timeUnit, - @Nullable ObservableSource other, + private Observable timeout0(long timeout, @NonNull TimeUnit unit, + @Nullable ObservableSource fallback, @NonNull Scheduler scheduler) { - Objects.requireNonNull(timeUnit, "timeUnit is null"); + Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new ObservableTimeoutTimed<>(this, timeout, timeUnit, scheduler, other)); + return RxJavaPlugins.onAssembly(new ObservableTimeoutTimed<>(this, timeout, unit, scheduler, fallback)); } @NonNull private Observable timeout0( @NonNull ObservableSource firstTimeoutIndicator, @NonNull Function> itemTimeoutIndicator, - @Nullable ObservableSource other) { + @Nullable ObservableSource fallback) { Objects.requireNonNull(itemTimeoutIndicator, "itemTimeoutIndicator is null"); - return RxJavaPlugins.onAssembly(new ObservableTimeout<>(this, firstTimeoutIndicator, itemTimeoutIndicator, other)); + return RxJavaPlugins.onAssembly(new ObservableTimeout<>(this, firstTimeoutIndicator, itemTimeoutIndicator, fallback)); } /** - * Returns an Observable that emits each item emitted by the source ObservableSource, wrapped in a + * Returns an {@code Observable} that emits each item emitted by the current {@code Observable}, wrapped in a * {@link Timed} object. *

- * + * *

*
Scheduler:
*
{@code timestamp} does not operate on any particular scheduler but uses the current time * from the {@code computation} {@link Scheduler}.
*
* - * @return an Observable that emits timestamped items from the source ObservableSource + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Timestamp */ @CheckReturnValue @@ -14241,20 +15077,20 @@ public final Observable> timestamp() { } /** - * Returns an Observable that emits each item emitted by the source ObservableSource, wrapped in a - * {@link Timed} object whose timestamps are provided by a specified Scheduler. + * Returns an {@code Observable} that emits each item emitted by the current {@code Observable}, wrapped in a + * {@link Timed} object whose timestamps are provided by a specified {@link Scheduler}. *

- * + * *

*
Scheduler:
*
This operator does not operate on any particular scheduler but uses the current time - * from the specified {@link Scheduler}.
+ * from the specified {@code Scheduler}. *
* * @param scheduler - * the {@link Scheduler} to use as a time source - * @return an Observable that emits timestamped items from the source ObservableSource with timestamps provided by - * the {@code scheduler} + * the {@code Scheduler} to use as a time source + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Timestamp */ @CheckReturnValue @@ -14265,10 +15101,10 @@ public final Observable> timestamp(@NonNull Scheduler scheduler) { } /** - * Returns an Observable that emits each item emitted by the source ObservableSource, wrapped in a + * Returns an {@code Observable} that emits each item emitted by the current {@code Observable}, wrapped in a * {@link Timed} object. *

- * + * *

*
Scheduler:
*
{@code timestamp} does not operate on any particular scheduler but uses the current time @@ -14276,7 +15112,8 @@ public final Observable> timestamp(@NonNull Scheduler scheduler) { *
* * @param unit the time unit for the current time - * @return an Observable that emits timestamped items from the source ObservableSource + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Timestamp */ @CheckReturnValue @@ -14287,21 +15124,21 @@ public final Observable> timestamp(@NonNull TimeUnit unit) { } /** - * Returns an Observable that emits each item emitted by the source ObservableSource, wrapped in a - * {@link Timed} object whose timestamps are provided by a specified Scheduler. + * Returns an {@code Observable} that emits each item emitted by the current {@code Observable}, wrapped in a + * {@link Timed} object whose timestamps are provided by a specified {@link Scheduler}. *

- * + * *

*
Scheduler:
*
This operator does not operate on any particular scheduler but uses the current time - * from the specified {@link Scheduler}.
+ * from the specified {@code Scheduler}. *
* * @param unit the time unit for the current time * @param scheduler - * the {@link Scheduler} to use as a time source - * @return an Observable that emits timestamped items from the source ObservableSource with timestamps provided by - * the {@code scheduler} + * the {@code Scheduler} to use as a time source + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Timestamp */ @CheckReturnValue @@ -14323,40 +15160,39 @@ public final Observable> timestamp(@NonNull TimeUnit unit, @NonNull Sch *
*

History: 2.1.7 - experimental * @param the resulting object type - * @param converter the function that receives the current Observable instance and returns a value + * @param converter the function that receives the current {@code Observable} instance and returns a value * @return the converted value - * @throws NullPointerException if converter is null + * @throws NullPointerException if {@code converter} is {@code null} * @since 2.2 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final R to(@NonNull ObservableConverter converter) { + public final <@NonNull R> R to(@NonNull ObservableConverter converter) { return Objects.requireNonNull(converter, "converter is null").apply(this); } /** - * Returns a Single that emits a single item, a list composed of all the items emitted by the - * finite source ObservableSource. + * Returns a {@link Single} that emits a single item, a {@link List} composed of all the items emitted by the + * current and finite {@code Observable}. *

- * + * *

- * Normally, an ObservableSource that returns multiple items will do so by invoking its {@link Observer}'s - * {@link Observer#onNext onNext} method for each such item. You can change this behavior, instructing the - * ObservableSource to compose a list of all of these items and then to invoke the Observer's {@code onNext} - * function once, passing it the entire list, by calling the ObservableSource's {@code toList} method prior to + * Normally, an {@link ObservableSource} that returns multiple items will do so by invoking its {@link Observer}'s + * {@link Observer#onNext onNext} method for each such item. You can change this behavior by having the + * operator to compose a list of all of these items and then to invoke the {@link SingleObserver}'s {@code onSuccess} + * method once, passing it the entire list, by calling the {@code Observable}'s {@code toList} method prior to * calling its {@link #subscribe} method. *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated list to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toList} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a Single that emits a single item: a List containing all of the items emitted by the source - * ObservableSource + * @return the new {@code Single} instance * @see ReactiveX operators documentation: To */ @CheckReturnValue @@ -14367,29 +15203,29 @@ public final R to(@NonNull ObservableConverter converter) { } /** - * Returns a Single that emits a single item, a list composed of all the items emitted by the - * finite source ObservableSource. + * Returns a {@link Single} that emits a single item, a {@link List} composed of all the items emitted by the + * current and finite {@code Observable}. *

- * + * *

- * Normally, an ObservableSource that returns multiple items will do so by invoking its {@link Observer}'s - * {@link Observer#onNext onNext} method for each such item. You can change this behavior, instructing the - * ObservableSource to compose a list of all of these items and then to invoke the Observer's {@code onNext} - * function once, passing it the entire list, by calling the ObservableSource's {@code toList} method prior to + * Normally, an {@link ObservableSource} that returns multiple items will do so by invoking its {@link Observer}'s + * {@link Observer#onNext onNext} method for each such item. You can change this behavior by having the + * operator to compose a list of all of these items and then to invoke the {@link SingleObserver}'s {@code onSuccess} + * method once, passing it the entire list, by calling the {@code Observable}'s {@code toList} method prior to * calling its {@link #subscribe} method. *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated list to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toList} does not operate by default on a particular {@link Scheduler}.
*
* * @param capacityHint - * the number of elements expected from the current Observable - * @return a Single that emits a single item: a List containing all of the items emitted by the source - * ObservableSource + * the number of elements expected from the current {@code Observable} + * @return the new {@code Single} instance + * @throws IllegalArgumentException if {@code capacityHint} is non-positive * @see ReactiveX operators documentation: To */ @CheckReturnValue @@ -14401,20 +15237,20 @@ public final R to(@NonNull ObservableConverter converter) { } /** - * Returns a Single that emits a single item, a list composed of all the items emitted by the - * finite source ObservableSource. + * Returns a {@link Single} that emits a single item, a {@link Collection} (subclass) composed of all the items emitted by the + * finite upstream {@code Observable}. *

* *

- * Normally, an ObservableSource that returns multiple items will do so by invoking its {@link Observer}'s - * {@link Observer#onNext onNext} method for each such item. You can change this behavior, instructing the - * ObservableSource to compose a list of all of these items and then to invoke the Observer's {@code onNext} - * function once, passing it the entire list, by calling the ObservableSource's {@code toList} method prior to + * Normally, an {@link ObservableSource} that returns multiple items will do so by invoking its {@link Observer}'s + * {@link Observer#onNext onNext} method for each such item. You can change this behavior by having the + * operator to compose a collection of all of these items and then to invoke the {@link SingleObserver}'s {@code onSuccess} + * method once, passing it the entire collection, by calling the {@code Observable}'s {@code toList} method prior to * calling its {@link #subscribe} method. *

* Note that this operator requires the upstream to signal {@code onComplete} for the accumulated collection to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toList} does not operate by default on a particular {@link Scheduler}.
@@ -14422,9 +15258,9 @@ public final R to(@NonNull ObservableConverter converter) { * * @param the subclass of a collection of Ts * @param collectionSupplier - * the Supplier returning the collection (for each individual Observer) to be filled in - * @return a Single that emits a single item: a List containing all of the items emitted by the source - * ObservableSource + * the {@link Supplier} returning the collection (for each individual {@code Observer}) to be filled in + * @return the new {@code Single} instance + * @throws NullPointerException if {@code collectionSupplier} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @@ -14436,17 +15272,17 @@ public final R to(@NonNull ObservableConverter converter) { } /** - * Returns a Single that emits a single HashMap containing all items emitted by the - * finite source ObservableSource, mapped by the keys returned by a specified + * Returns a {@link Single} that emits a single {@link HashMap} containing all items emitted by the + * current and finite {@code Observable}, mapped by the keys returned by a specified * {@code keySelector} function. *

- * + * *

- * If more than one source item maps to the same key, the HashMap will contain the latest of those items. + * If more than one source item maps to the same key, the {@code HashMap} will contain the latest of those items. *

- * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated map to + * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated {@code HashMap} to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toMap} does not operate by default on a particular {@link Scheduler}.
@@ -14454,50 +15290,50 @@ public final R to(@NonNull ObservableConverter converter) { * * @param the key type of the Map * @param keySelector - * the function that extracts the key from a source item to be used in the HashMap - * @return a Single that emits a single item: a HashMap containing the mapped items from the source - * ObservableSource + * the function that extracts the key from a source item to be used in the {@code HashMap} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single<@NonNull Map> toMap(@NonNull Function keySelector) { + public final <@NonNull K> Single<@NonNull Map> toMap(@NonNull Function keySelector) { Objects.requireNonNull(keySelector, "keySelector is null"); return collect(HashMapSupplier.asSupplier(), Functions.toMapKeySelector(keySelector)); } /** - * Returns a Single that emits a single HashMap containing values corresponding to items emitted by the - * finite source ObservableSource, mapped by the keys returned by a specified {@code keySelector} function. + * Returns a {@link Single} that emits a single {@link HashMap} containing values corresponding to items emitted by the + * current and finite {@code Observable}, mapped by the keys and values returned by the given selector functions. *

- * + * *

- * If more than one source item maps to the same key, the HashMap will contain a single entry that + * If more than one source item maps to the same key, the {@code HashMap} will contain a single entry that * corresponds to the latest of those items. *

- * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated map to + * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated {@code HashMap} to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toMap} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the key type of the Map - * @param the value type of the Map + * @param the key type of the {@code HashMap} + * @param the value type of the {@code HashMap} * @param keySelector - * the function that extracts the key from a source item to be used in the HashMap + * the function that extracts the key from a source item to be used in the {@code HashMap} * @param valueSelector - * the function that extracts the value from a source item to be used in the HashMap - * @return a Single that emits a single item: a HashMap containing the mapped items from the source - * ObservableSource + * the function that extracts the value from a source item to be used in the {@code HashMap} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code keySelector} or {@code valueSelector} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single> toMap( + public final <@NonNull K, @NonNull V> Single> toMap( @NonNull Function keySelector, @NonNull Function valueSelector) { Objects.requireNonNull(keySelector, "keySelector is null"); @@ -14506,35 +15342,35 @@ public final Single> toMap( } /** - * Returns a Single that emits a single Map, returned by a specified {@code mapFactory} function, that - * contains keys and values extracted from the items emitted by the finite source ObservableSource. + * Returns a {@link Single} that emits a single {@link Map} (subclass), returned by a specified {@code mapFactory} function, that + * contains keys and values extracted from the items, via selector functions, emitted by the current and finite {@code Observable}. *

- * + * *

- * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated map to + * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated {@code Map} to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toMap} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the key type of the Map - * @param the value type of the Map + * @param the key type of the {@code Map} + * @param the value type of the {@code Map} * @param keySelector - * the function that extracts the key from a source item to be used in the Map + * the function that extracts the key from a source item to be used in the {@code Map} * @param valueSelector - * the function that extracts the value from the source items to be used as value in the Map + * the function that extracts the value from the source items to be used as value in the {@code Map} * @param mapSupplier - * the function that returns a Map instance to be used - * @return a Single that emits a single item: a Map that contains the mapped items emitted by the - * source ObservableSource + * the function that returns a {@code Map} instance to be used + * @return the new {@code Single} instance + * @throws NullPointerException if {@code keySelector}, {@code valueSelector} or {@code mapSupplier} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single> toMap( + public final <@NonNull K, @NonNull V> Single> toMap( @NonNull Function keySelector, @NonNull Function valueSelector, @NonNull Supplier> mapSupplier) { @@ -14545,30 +15381,30 @@ public final Single> toMap( } /** - * Returns a Single that emits a single HashMap that contains an ArrayList of items emitted by the - * finite source ObservableSource keyed by a specified {@code keySelector} function. + * Returns a {@link Single} that emits a single {@link HashMap} that contains an {@link ArrayList} of items emitted by the + * current and finite {@code Observable} keyed by a specified {@code keySelector} function. *

- * + * *

- * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated map to + * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated {@code HashMap} to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toMultimap} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the key type of the Map + * @param the key type of the {@code HashMap} * @param keySelector - * the function that extracts the key from the source items to be used as key in the HashMap - * @return a Single that emits a single item: a HashMap that contains an ArrayList of items mapped from - * the source ObservableSource + * the function that extracts the key from the source items to be used as key in the {@code HashMap} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single<@NonNull Map>> toMultimap(@NonNull Function keySelector) { + public final <@NonNull K> Single<@NonNull Map>> toMultimap(@NonNull Function keySelector) { Function valueSelector = Functions.identity(); Supplier>> mapSupplier = HashMapSupplier.asSupplier(); Function> collectionFactory = ArrayListSupplier.asFunction(); @@ -14576,68 +15412,72 @@ public final Single> toMap( } /** - * Returns a Single that emits a single HashMap that contains an ArrayList of values extracted by a - * specified {@code valueSelector} function from items emitted by the finite source ObservableSource, + * Returns a {@link Single} that emits a single {@link HashMap} that contains an {@link ArrayList} of values extracted by a + * specified {@code valueSelector} function from items emitted by the current and finite {@code Observable}, * keyed by a specified {@code keySelector} function. *

- * + * *

- * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated map to + * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated {@code HashMap} to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toMultimap} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the key type of the Map - * @param the value type of the Map + * @param the key type of the {@code HashMap} + * @param the value type of the {@code HashMap} * @param keySelector - * the function that extracts a key from the source items to be used as key in the HashMap + * the function that extracts a key from the source items to be used as key in the {@code HashMap} * @param valueSelector - * the function that extracts a value from the source items to be used as value in the HashMap - * @return a Single that emits a single item: a HashMap that contains an ArrayList of items mapped from - * the source ObservableSource + * the function that extracts a value from the source items to be used as value in the {@code HashMap} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code keySelector} or {@code valueSelector} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single<@NonNull Map>> toMultimap(@NonNull Function keySelector, Function valueSelector) { + public final <@NonNull K, @NonNull V> Single<@NonNull Map>> toMultimap(@NonNull Function keySelector, Function valueSelector) { Supplier>> mapSupplier = HashMapSupplier.asSupplier(); Function> collectionFactory = ArrayListSupplier.asFunction(); return toMultimap(keySelector, valueSelector, mapSupplier, collectionFactory); } /** - * Returns a Single that emits a single Map, returned by a specified {@code mapFactory} function, that - * contains a custom collection of values, extracted by a specified {@code valueSelector} function from - * items emitted by the source ObservableSource, and keyed by the {@code keySelector} function. + * Returns a {@link Single} that emits a single {@code Map} (subclass), returned by a specified {@code mapFactory} function, that + * contains a custom {@link Collection} of values, extracted by a specified {@code valueSelector} function from + * items emitted by the current and finite {@code Observable}, and keyed by the {@code keySelector} function. + *

+ * *

- * + * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated {@code Map} to + * be emitted. Sources that are infinite and never complete will never emit anything through this + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toMultimap} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the key type of the Map - * @param the value type of the Map + * @param the key type of the {@code Map} + * @param the value type of the {@code Map} * @param keySelector - * the function that extracts a key from the source items to be used as the key in the Map + * the function that extracts a key from the source items to be used as the key in the {@code Map} * @param valueSelector - * the function that extracts a value from the source items to be used as the value in the Map + * the function that extracts a value from the source items to be used as the value in the {@code Map} * @param mapSupplier - * the function that returns a Map instance to be used + * the function that returns a {@code Map} instance to be used * @param collectionFactory - * the function that returns a Collection instance for a particular key to be used in the Map - * @return a Single that emits a single item: a Map that contains the collection of mapped items from - * the source ObservableSource + * the function that returns a {@code Collection} instance for a particular key to be used in the {@code Map} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code keySelector}, {@code valueSelector}, {@code mapSupplier} or {@code collectionFactory} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single<@NonNull Map>> toMultimap( + public final <@NonNull K, @NonNull V> Single<@NonNull Map>> toMultimap( @NonNull Function keySelector, @NonNull Function valueSelector, @NonNull Supplier>> mapSupplier, @@ -14650,36 +15490,36 @@ public final Single> toMap( } /** - * Returns a Single that emits a single Map, returned by a specified {@code mapFactory} function, that - * contains an ArrayList of values, extracted by a specified {@code valueSelector} function from items - * emitted by the finite source ObservableSource and keyed by the {@code keySelector} function. + * Returns a {@link Single} that emits a single {@link Map} (subclass), returned by a specified {@code mapFactory} function, that + * contains an {@link ArrayList} of values, extracted by a specified {@code valueSelector} function from items + * emitted by the current and finite {@code Observable} and keyed by the {@code keySelector} function. *

- * + * *

- * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated map to + * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated {@code Map} to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toMultimap} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the key type of the Map - * @param the value type of the Map + * @param the key type of the {@code Map} + * @param the value type of the {@code Map} * @param keySelector - * the function that extracts a key from the source items to be used as the key in the Map + * the function that extracts a key from the source items to be used as the key in the {@code Map} * @param valueSelector - * the function that extracts a value from the source items to be used as the value in the Map + * the function that extracts a value from the source items to be used as the value in the {@code Map} * @param mapSupplier - * the function that returns a Map instance to be used - * @return a Single that emits a single item: a Map that contains a list items mapped from the source - * ObservableSource + * the function that returns a {@code Map} instance to be used + * @return the new {@code Single} instance + * @throws NullPointerException if {@code keySelector}, {@code valueSelector} or {@code mapSupplier} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single<@NonNull Map>> toMultimap( + public final <@NonNull K, @NonNull V> Single<@NonNull Map>> toMultimap( @NonNull Function keySelector, @NonNull Function valueSelector, @NonNull Supplier>> mapSupplier @@ -14688,7 +15528,7 @@ public final Single> toMap( } /** - * Converts the current Observable into a Flowable by applying the specified backpressure strategy. + * Converts the current {@code Observable} into a {@link Flowable} by applying the specified backpressure strategy. *

* Marble diagrams for the various backpressure strategies are as follows: *

    @@ -14702,7 +15542,7 @@ public final Single> toMap( * *
  • {@link BackpressureStrategy#LATEST} *

    - * + * *

  • *
  • {@link BackpressureStrategy#ERROR} *

    @@ -14710,7 +15550,7 @@ public final Single> toMap( *

  • *
  • {@link BackpressureStrategy#MISSING} *

    - * + * *

  • *
*
@@ -14721,15 +15561,16 @@ public final Single> toMap( *
* * @param strategy the backpressure strategy to apply - * @return the new Flowable instance + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code strategy} is {@code null} */ @BackpressureSupport(BackpressureKind.SPECIAL) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final Flowable toFlowable(@NonNull BackpressureStrategy strategy) { + Objects.requireNonNull(strategy, "strategy is null"); Flowable f = new FlowableFromObservable<>(this); - switch (strategy) { case DROP: return f.onBackpressureDrop(); @@ -14745,53 +15586,55 @@ public final Flowable toFlowable(@NonNull BackpressureStrategy strategy) { } /** - * Returns a Single that emits a list that contains the items emitted by the finite source ObservableSource, in a - * sorted order. Each item emitted by the ObservableSource must implement {@link Comparable} with respect to all + * Returns a {@link Single} that emits a {@link List} that contains the items emitted by the current and finite {@code Observable}, in a + * sorted order. Each item emitted by the current {@code Observable} must implement {@link Comparable} with respect to all * other items in the sequence. * - *

If any item emitted by this Observable does not implement {@link Comparable} with respect to - * all other items emitted by this Observable, no items will be emitted and the - * sequence is terminated with a {@link ClassCastException}. *

- * + * If any item emitted by the current {@code Observable} does not implement {@code Comparable} with respect to + * all other items emitted by the current {@code Observable}, no items will be emitted and the + * sequence is terminated with a {@link ClassCastException}. *

- * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated list to + * + *

+ * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated {@code List} to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toSortedList} does not operate by default on a particular {@link Scheduler}.
*
- * @return a Single that emits a list that contains the items emitted by the source ObservableSource in - * sorted order + * @return the new {@code Single} instance * @see ReactiveX operators documentation: To + * @see #toSortedList(int) + * @see #toSortedList(Comparator) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final Single<@NonNull List> toSortedList() { - return toSortedList(Functions.naturalOrder()); + return toSortedList(Functions.naturalComparator()); } /** - * Returns a Single that emits a list that contains the items emitted by the finite source ObservableSource, in a + * Returns a {@link Single} that emits a {@link List} that contains the items emitted by the current and finite {@code Observable}, in a * sorted order based on a specified comparison function. *

- * + * *

- * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated list to + * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated {@code List} to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toSortedList} does not operate by default on a particular {@link Scheduler}.
*
* * @param comparator - * a function that compares two items emitted by the source ObservableSource and returns an Integer + * a function that compares two items emitted by the current {@code Observable} and returns an {@code int} * that indicates their sort order - * @return a Single that emits a list that contains the items emitted by the source ObservableSource in - * sorted order + * @return the new {@code Single} instance + * @throws NullPointerException if {@code comparator} is {@code null} * @see ReactiveX operators documentation: To */ @CheckReturnValue @@ -14803,26 +15646,27 @@ public final Flowable toFlowable(@NonNull BackpressureStrategy strategy) { } /** - * Returns a Single that emits a list that contains the items emitted by the finite source ObservableSource, in a + * Returns a {@link Single} that emits a {@link List} that contains the items emitted by the current and finite {@code Observable}, in a * sorted order based on a specified comparison function. *

- * + * *

- * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated list to + * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated {@code List} to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toSortedList} does not operate by default on a particular {@link Scheduler}.
*
* * @param comparator - * a function that compares two items emitted by the source ObservableSource and returns an Integer + * a function that compares two items emitted by the current {@code Observable} and returns an {@code int} * that indicates their sort order * @param capacityHint - * the initial capacity of the ArrayList used to accumulate items before sorting - * @return a Single that emits a list that contains the items emitted by the source ObservableSource in - * sorted order + * the initial capacity of the {@code List} used to accumulate items before sorting + * @return the new {@code Single} instance + * @throws NullPointerException if {@code comparator} is {@code null} + * @throws IllegalArgumentException if {@code capacityHint} is non-positive * @see ReactiveX operators documentation: To * @since 2.0 */ @@ -14835,52 +15679,53 @@ public final Flowable toFlowable(@NonNull BackpressureStrategy strategy) { } /** - * Returns a Single that emits a list that contains the items emitted by the finite source ObservableSource, in a - * sorted order. Each item emitted by the ObservableSource must implement {@link Comparable} with respect to all + * Returns a {@link Single} that emits a {@link List} that contains the items emitted by the current and finite {@code Observable}, in a + * sorted order. Each item emitted by the current {@code Observable} must implement {@link Comparable} with respect to all * other items in the sequence. - * - *

If any item emitted by this Observable does not implement {@link Comparable} with respect to - * all other items emitted by this Observable, no items will be emitted and the - * sequence is terminated with a {@link ClassCastException}. *

- * + * If any item emitted by the current {@code Observable} does not implement {@code Comparable} with respect to + * all other items emitted by the current {@code Observable}, no items will be emitted and the + * sequence is terminated with a {@link ClassCastException}. *

- * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated list to + * + *

+ * Note that this operator requires the upstream to signal {@code onComplete} for the accumulated {@code List} to * be emitted. Sources that are infinite and never complete will never emit anything through this - * operator and an infinite source may lead to a fatal {@code OutOfMemoryError}. + * operator and an infinite source may lead to a fatal {@link OutOfMemoryError}. *

*
Scheduler:
*
{@code toSortedList} does not operate by default on a particular {@link Scheduler}.
*
* * @param capacityHint - * the initial capacity of the ArrayList used to accumulate items before sorting - * @return a Single that emits a list that contains the items emitted by the source ObservableSource in - * sorted order + * the initial capacity of the {@code List} used to accumulate items before sorting + * @return the new {@code Single} instance + * @throws IllegalArgumentException if {@code capacityHint} is non-positive * @see ReactiveX operators documentation: To * @since 2.0 + * @see #toSortedList(Comparator, int) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final Single<@NonNull List> toSortedList(int capacityHint) { - return toSortedList(Functions.naturalOrder(), capacityHint); + return toSortedList(Functions.naturalComparator(), capacityHint); } /** - * Modifies the source ObservableSource so that subscribers will dispose it on a specified - * {@link Scheduler}. + * Return an {@code Observable} that schedules the downstream {@link Observer}s' {@code dispose} calls + * aimed at the current {@code Observable} on the given {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param scheduler - * the {@link Scheduler} to perform the call to dispose() of the upstream Disposable - * @return the source ObservableSource modified so that its dispose() calls happen on the specified - * {@link Scheduler} + * the {@code Scheduler} to perform the call to {@code dispose()} of the upstream {@link Disposable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: SubscribeOn */ @CheckReturnValue @@ -14892,12 +15737,12 @@ public final Observable unsubscribeOn(@NonNull Scheduler scheduler) { } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping windows, each containing {@code count} items. When the source - * ObservableSource completes or encounters an error, the resulting ObservableSource emits the current window and - * propagates the notification from the source ObservableSource. + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping windows, each containing {@code count} items. When the current + * {@code Observable} completes or encounters an error, the resulting {@code Observable} emits the current window and + * propagates the notification from the current {@code Observable}. *

- * + * *

*
Scheduler:
*
This version of {@code window} does not operate by default on a particular {@link Scheduler}.
@@ -14905,9 +15750,8 @@ public final Observable unsubscribeOn(@NonNull Scheduler scheduler) { * * @param count * the maximum size of each window before it should be emitted - * @return an Observable that emits connected, non-overlapping windows, each containing at most - * {@code count} items from the source ObservableSource - * @throws IllegalArgumentException if either count is non-positive + * @return the new {@code Observable} instance + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -14918,12 +15762,12 @@ public final Observable> window(long count) { } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource emits windows every {@code skip} items, each containing no more than {@code count} items. When - * the source ObservableSource completes or encounters an error, the resulting ObservableSource emits the current window - * and propagates the notification from the source ObservableSource. + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits windows every {@code skip} items, each containing no more than {@code count} items. When + * the current {@code Observable} completes or encounters an error, the resulting {@code Observable} emits the current window + * and propagates the notification from the current {@code Observable}. *

- * + * *

*
Scheduler:
*
This version of {@code window} does not operate by default on a particular {@link Scheduler}.
@@ -14934,9 +15778,8 @@ public final Observable> window(long count) { * @param skip * how many items need to be skipped before starting a new window. Note that if {@code skip} and * {@code count} are equal this is the same operation as {@link #window(long)}. - * @return an Observable that emits windows every {@code skip} items containing at most {@code count} items - * from the source ObservableSource - * @throws IllegalArgumentException if either count or skip is non-positive + * @return the new {@code Observable} instance + * @throws IllegalArgumentException if {@code count} or {@code skip} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -14947,12 +15790,12 @@ public final Observable> window(long count, long skip) { } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource emits windows every {@code skip} items, each containing no more than {@code count} items. When - * the source ObservableSource completes or encounters an error, the resulting ObservableSource emits the current window - * and propagates the notification from the source ObservableSource. + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits windows every {@code skip} items, each containing no more than {@code count} items. When + * the current {@code Observable} completes or encounters an error, the resulting {@code Observable} emits the current window + * and propagates the notification from the current {@code Observable}. *

- * + * *

*
Scheduler:
*
This version of {@code window} does not operate by default on a particular {@link Scheduler}.
@@ -14965,9 +15808,8 @@ public final Observable> window(long count, long skip) { * {@code count} are equal this is the same operation as {@link #window(long)}. * @param bufferSize * the capacity hint for the buffer in the inner windows - * @return an Observable that emits windows every {@code skip} items containing at most {@code count} items - * from the source ObservableSource - * @throws IllegalArgumentException if either count or skip is non-positive + * @return the new {@code Observable} instance + * @throws IllegalArgumentException if {@code count}, {@code skip} or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -14981,13 +15823,13 @@ public final Observable> window(long count, long skip, int bufferS } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource starts a new window periodically, as determined by the {@code timeskip} argument. It emits - * each window after a fixed timespan, specified by the {@code timespan} argument. When the source - * ObservableSource completes or ObservableSource completes or encounters an error, the resulting ObservableSource emits the - * current window and propagates the notification from the source ObservableSource. + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} starts a new window periodically, as determined by the {@code timeskip} argument. It emits + * each window after a fixed timespan, specified by the {@code timespan} argument. When the current + * {@code Observable} completes or encounters an error, the resulting {@code Observable} emits the + * current window and propagates the notification from the current {@code Observable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15004,7 +15846,9 @@ public final Observable> window(long count, long skip, int bufferS * the period of time after which a new window will be created * @param unit * the unit of time that applies to the {@code timespan} and {@code timeskip} arguments - * @return an Observable that emits new windows periodically as a fixed timespan elapses + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code timespan} or {@code timeskip} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -15015,13 +15859,13 @@ public final Observable> window(long timespan, long timeskip, @Non } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource starts a new window periodically, as determined by the {@code timeskip} argument. It emits - * each window after a fixed timespan, specified by the {@code timespan} argument. When the source - * ObservableSource completes or ObservableSource completes or encounters an error, the resulting ObservableSource emits the - * current window and propagates the notification from the source ObservableSource. + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} starts a new window periodically, as determined by the {@code timeskip} argument. It emits + * each window after a fixed timespan, specified by the {@code timespan} argument. When the current + * {@code Observable} completes or encounters an error, the resulting {@code Observable} emits the + * current window and propagates the notification from the current {@code Observable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15039,8 +15883,10 @@ public final Observable> window(long timespan, long timeskip, @Non * @param unit * the unit of time that applies to the {@code timespan} and {@code timeskip} arguments * @param scheduler - * the {@link Scheduler} to use when determining the end and start of a window - * @return an Observable that emits new windows periodically as a fixed timespan elapses + * the {@code Scheduler} to use when determining the end and start of a window + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code timespan} or {@code timeskip} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -15051,13 +15897,13 @@ public final Observable> window(long timespan, long timeskip, @Non } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource starts a new window periodically, as determined by the {@code timeskip} argument. It emits - * each window after a fixed timespan, specified by the {@code timespan} argument. When the source - * ObservableSource completes or ObservableSource completes or encounters an error, the resulting ObservableSource emits the - * current window and propagates the notification from the source ObservableSource. + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} starts a new window periodically, as determined by the {@code timeskip} argument. It emits + * each window after a fixed timespan, specified by the {@code timespan} argument. When the current + * {@code Observable} completes or encounters an error, the resulting {@code Observable} emits the + * current window and propagates the notification from the current {@code Observable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15075,10 +15921,12 @@ public final Observable> window(long timespan, long timeskip, @Non * @param unit * the unit of time that applies to the {@code timespan} and {@code timeskip} arguments * @param scheduler - * the {@link Scheduler} to use when determining the end and start of a window + * the {@code Scheduler} to use when determining the end and start of a window * @param bufferSize * the capacity hint for the buffer in the inner windows - * @return an Observable that emits new windows periodically as a fixed timespan elapses + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code timespan}, {@code timeskip} or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -15094,12 +15942,12 @@ public final Observable> window(long timespan, long timeskip, @Non } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping windows, each of a fixed duration specified by the - * {@code timespan} argument. When the source ObservableSource completes or encounters an error, the resulting - * ObservableSource emits the current window and propagates the notification from the source ObservableSource. + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping windows, each of a fixed duration specified by the + * {@code timespan} argument. When the current {@code Observable} completes or encounters an error, the resulting + * {@code Observable} emits the current window and propagates the notification from the current {@code Observable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15115,8 +15963,8 @@ public final Observable> window(long timespan, long timeskip, @Non * new window * @param unit * the unit of time that applies to the {@code timespan} argument - * @return an Observable that emits connected, non-overlapping windows representing items emitted by the - * source ObservableSource during fixed, consecutive durations + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -15127,13 +15975,13 @@ public final Observable> window(long timespan, @NonNull TimeUnit u } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping windows, each of a fixed duration as specified by the + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping windows, each of a fixed duration as specified by the * {@code timespan} argument or a maximum size as specified by the {@code count} argument (whichever is - * reached first). When the source ObservableSource completes or encounters an error, the resulting ObservableSource - * emits the current window and propagates the notification from the source ObservableSource. + * reached first). When the current {@code Observable} completes or encounters an error, the resulting {@code Observable} + * emits the current window and propagates the notification from the current {@code Observable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15151,9 +15999,9 @@ public final Observable> window(long timespan, @NonNull TimeUnit u * the unit of time that applies to the {@code timespan} argument * @param count * the maximum size of each window before it should be emitted - * @return an Observable that emits connected, non-overlapping windows of items from the source ObservableSource - * that were emitted during a fixed duration of time or when the window has reached maximum capacity - * (whichever occurs first) + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -15165,13 +16013,13 @@ public final Observable> window(long timespan, @NonNull TimeUnit u } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping windows, each of a fixed duration as specified by the + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping windows, each of a fixed duration as specified by the * {@code timespan} argument or a maximum size as specified by the {@code count} argument (whichever is - * reached first). When the source ObservableSource completes or encounters an error, the resulting ObservableSource - * emits the current window and propagates the notification from the source ObservableSource. + * reached first). When the current {@code Observable} completes or encounters an error, the resulting {@code Observable} + * emits the current window and propagates the notification from the current {@code Observable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15190,10 +16038,10 @@ public final Observable> window(long timespan, @NonNull TimeUnit u * @param count * the maximum size of each window before it should be emitted * @param restart - * if true, when a window reaches the capacity limit, the timer is restarted as well - * @return an Observable that emits connected, non-overlapping windows of items from the source ObservableSource - * that were emitted during a fixed duration of time or when the window has reached maximum capacity - * (whichever occurs first) + * if {@code true}, when a window reaches the capacity limit, the timer is restarted as well + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -15205,12 +16053,12 @@ public final Observable> window(long timespan, @NonNull TimeUnit u } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping windows, each of a fixed duration as specified by the - * {@code timespan} argument. When the source ObservableSource completes or encounters an error, the resulting - * ObservableSource emits the current window and propagates the notification from the source ObservableSource. + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping windows, each of a fixed duration as specified by the + * {@code timespan} argument. When the current {@code Observable} completes or encounters an error, the resulting + * {@code Observable} emits the current window and propagates the notification from the current {@code Observable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15227,9 +16075,9 @@ public final Observable> window(long timespan, @NonNull TimeUnit u * @param unit * the unit of time which applies to the {@code timespan} argument * @param scheduler - * the {@link Scheduler} to use when determining the end and start of a window - * @return an Observable that emits connected, non-overlapping windows containing items emitted by the - * source ObservableSource within a fixed duration + * the {@code Scheduler} to use when determining the end and start of a window + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -15241,13 +16089,13 @@ public final Observable> window(long timespan, @NonNull TimeUnit u } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping windows, each of a fixed duration specified by the + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping windows, each of a fixed duration specified by the * {@code timespan} argument or a maximum size specified by the {@code count} argument (whichever is reached - * first). When the source ObservableSource completes or encounters an error, the resulting ObservableSource emits the - * current window and propagates the notification from the source ObservableSource. + * first). When the current {@code Observable} completes or encounters an error, the resulting {@code Observable} emits the + * current window and propagates the notification from the current {@code Observable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15266,10 +16114,10 @@ public final Observable> window(long timespan, @NonNull TimeUnit u * @param count * the maximum size of each window before it should be emitted * @param scheduler - * the {@link Scheduler} to use when determining the end and start of a window - * @return an Observable that emits connected, non-overlapping windows of items from the source ObservableSource - * that were emitted during a fixed duration of time or when the window has reached maximum capacity - * (whichever occurs first) + * the {@code Scheduler} to use when determining the end and start of a window + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -15281,13 +16129,13 @@ public final Observable> window(long timespan, @NonNull TimeUnit u } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping windows, each of a fixed duration specified by the + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping windows, each of a fixed duration specified by the * {@code timespan} argument or a maximum size specified by the {@code count} argument (whichever is reached - * first). When the source ObservableSource completes or encounters an error, the resulting ObservableSource emits the - * current window and propagates the notification from the source ObservableSource. + * first). When the current {@code Observable} completes or encounters an error, the resulting {@code Observable} emits the + * current window and propagates the notification from the current {@code Observable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15306,12 +16154,12 @@ public final Observable> window(long timespan, @NonNull TimeUnit u * @param count * the maximum size of each window before it should be emitted * @param scheduler - * the {@link Scheduler} to use when determining the end and start of a window + * the {@code Scheduler} to use when determining the end and start of a window * @param restart - * if true, when a window reaches the capacity limit, the timer is restarted as well - * @return an Observable that emits connected, non-overlapping windows of items from the source ObservableSource - * that were emitted during a fixed duration of time or when the window has reached maximum capacity - * (whichever occurs first) + * if {@code true}, when a window reaches the capacity limit, the timer is restarted as well + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code count} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -15323,13 +16171,13 @@ public final Observable> window(long timespan, @NonNull TimeUnit u } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource emits connected, non-overlapping windows, each of a fixed duration specified by the + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits connected, non-overlapping windows, each of a fixed duration specified by the * {@code timespan} argument or a maximum size specified by the {@code count} argument (whichever is reached - * first). When the source ObservableSource completes or encounters an error, the resulting ObservableSource emits the - * current window and propagates the notification from the source ObservableSource. + * first). When the current {@code Observable} completes or encounters an error, the resulting {@code Observable} emits the + * current window and propagates the notification from the current {@code Observable}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15348,14 +16196,14 @@ public final Observable> window(long timespan, @NonNull TimeUnit u * @param count * the maximum size of each window before it should be emitted * @param scheduler - * the {@link Scheduler} to use when determining the end and start of a window + * the {@code Scheduler} to use when determining the end and start of a window * @param restart - * if true, when a window reaches the capacity limit, the timer is restarted as well + * if {@code true}, when a window reaches the capacity limit, the timer is restarted as well * @param bufferSize * the capacity hint for the buffer in the inner windows - * @return an Observable that emits connected, non-overlapping windows of items from the source ObservableSource - * that were emitted during a fixed duration of time or when the window has reached maximum capacity - * (whichever occurs first) + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code count} or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @@ -15372,11 +16220,11 @@ public final Observable> window( } /** - * Returns an Observable that emits non-overlapping windows of items it collects from the source ObservableSource + * Returns an {@code Observable} that emits non-overlapping windows of items it collects from the current {@code Observable} * where the boundary of each window is determined by the items emitted from a specified boundary-governing - * ObservableSource. + * {@link ObservableSource}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15389,26 +16237,25 @@ public final Observable> window( * * @param * the window element type (ignored) - * @param boundary - * an ObservableSource whose emitted items close and open windows - * @return an Observable that emits non-overlapping windows of items it collects from the source ObservableSource - * where the boundary of each window is determined by the items emitted from the {@code boundary} - * ObservableSource + * @param boundaryIndicator + * an {@code ObservableSource} whose emitted items close and open windows + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code boundaryIndicator} is {@code null} * @see ReactiveX operators documentation: Window */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable> window(@NonNull ObservableSource boundary) { - return window(boundary, bufferSize()); + public final <@NonNull B> Observable> window(@NonNull ObservableSource boundaryIndicator) { + return window(boundaryIndicator, bufferSize()); } /** - * Returns an Observable that emits non-overlapping windows of items it collects from the source ObservableSource + * Returns an {@code Observable} that emits non-overlapping windows of items it collects from the current {@code Observable} * where the boundary of each window is determined by the items emitted from a specified boundary-governing - * ObservableSource. + * {@link ObservableSource}. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15421,31 +16268,31 @@ public final Observable> window(@NonNull ObservableSource b * * @param * the window element type (ignored) - * @param boundary - * an ObservableSource whose emitted items close and open windows + * @param boundaryIndicator + * an {@code ObservableSource} whose emitted items close and open windows * @param bufferSize * the capacity hint for the buffer in the inner windows - * @return an Observable that emits non-overlapping windows of items it collects from the source ObservableSource - * where the boundary of each window is determined by the items emitted from the {@code boundary} - * ObservableSource + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code boundaryIndicator} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable> window(@NonNull ObservableSource boundary, int bufferSize) { - Objects.requireNonNull(boundary, "boundary is null"); + public final <@NonNull B> Observable> window(@NonNull ObservableSource boundaryIndicator, int bufferSize) { + Objects.requireNonNull(boundaryIndicator, "boundaryIndicator is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); - return RxJavaPlugins.onAssembly(new ObservableWindowBoundary<>(this, boundary, bufferSize)); + return RxJavaPlugins.onAssembly(new ObservableWindowBoundary<>(this, boundaryIndicator, bufferSize)); } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource emits windows that contain those items emitted by the source ObservableSource between the time when - * the {@code openingIndicator} ObservableSource emits an item and when the ObservableSource returned by + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits windows that contain those items emitted by the current {@code Observable} between the time when + * the {@code openingIndicator} {@link ObservableSource} emits an item and when the {@code ObservableSource} returned by * {@code closingIndicator} emits an item. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15456,33 +16303,33 @@ public final Observable> window(@NonNull ObservableSource b *

This version of {@code window} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the element type of the window-opening ObservableSource - * @param the element type of the window-closing ObservableSources + * @param the element type of the window-opening {@code ObservableSource} + * @param the element type of the window-closing {@code ObservableSource}s * @param openingIndicator - * an ObservableSource that, when it emits an item, causes another window to be created + * an {@code ObservableSource} that, when it emits an item, causes another window to be created * @param closingIndicator - * a {@link Function} that produces an ObservableSource for every window created. When this ObservableSource - * emits an item, the associated window is closed and emitted - * @return an Observable that emits windows of items emitted by the source ObservableSource that are governed by - * the specified window-governing ObservableSources + * a {@link Function} that produces an {@code ObservableSource} for every window created. When this indicator {@code ObservableSource} + * emits an item, the associated window is completed + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code openingIndicator} or {@code closingIndicator} is {@code null} * @see ReactiveX operators documentation: Window */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable> window( + public final <@NonNull U, @NonNull V> Observable> window( @NonNull ObservableSource openingIndicator, @NonNull Function> closingIndicator) { return window(openingIndicator, closingIndicator, bufferSize()); } /** - * Returns an Observable that emits windows of items it collects from the source ObservableSource. The resulting - * ObservableSource emits windows that contain those items emitted by the source ObservableSource between the time when - * the {@code openingIndicator} ObservableSource emits an item and when the ObservableSource returned by + * Returns an {@code Observable} that emits windows of items it collects from the current {@code Observable}. The resulting + * {@code Observable} emits windows that contain those items emitted by the current {@code Observable} between the time when + * the {@code openingIndicator} {@link ObservableSource} emits an item and when the {@code ObservableSource} returned by * {@code closingIndicator} emits an item. *

- * + * *

* Note that ignoring windows or subscribing later (i.e., on another thread) will result in * so-called window abandonment where a window may not contain any elements. In this case, subsequent @@ -15493,23 +16340,24 @@ public final Observable> window( *

This version of {@code window} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the element type of the window-opening ObservableSource - * @param the element type of the window-closing ObservableSources + * @param the element type of the window-opening {@code ObservableSource} + * @param the element type of the window-closing {@code ObservableSource}s * @param openingIndicator - * an ObservableSource that, when it emits an item, causes another window to be created + * an {@code ObservableSource} that, when it emits an item, causes another window to be created * @param closingIndicator - * a {@link Function} that produces an ObservableSource for every window created. When this ObservableSource - * emits an item, the associated window is closed and emitted + * a {@link Function} that produces an {@code ObservableSource} for every window created. When this indicator {@code ObservableSource} + * emits an item, the associated window is completed * @param bufferSize * the capacity hint for the buffer in the inner windows - * @return an Observable that emits windows of items emitted by the source ObservableSource that are governed by - * the specified window-governing ObservableSources + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code openingIndicator} or {@code closingIndicator} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Window */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable> window( + public final <@NonNull U, @NonNull V> Observable> window( @NonNull ObservableSource openingIndicator, @NonNull Function> closingIndicator, int bufferSize) { Objects.requireNonNull(openingIndicator, "openingIndicator is null"); @@ -15519,33 +16367,39 @@ public final Observable> window( } /** - * Merges the specified ObservableSource into this ObservableSource sequence by using the {@code resultSelector} - * function only when the source ObservableSource (this instance) emits an item. + * Merges the specified {@link ObservableSource} into the current {@code Observable} sequence by using the {@code resultSelector} + * function only when the current {@code Observable} emits an item. + * + *

Note that this operator doesn't emit anything until the other source has produced at + * least one value. The resulting emission only happens when the current {@code Observable} emits (and + * not when the other source emits, unlike combineLatest). + * If the other source doesn't produce any value and just completes, the sequence is completed immediately. + * If the upstream completes before the other source has produced at least one value, the sequence completes + * without emission. *

- * + * * *

*
Scheduler:
*
This operator, by default, doesn't run any particular {@link Scheduler}.
*
* - * @param the element type of the other ObservableSource + * @param the element type of the other {@code ObservableSource} * @param the result type of the combination * @param other - * the other ObservableSource + * the other {@code ObservableSource} * @param combiner - * the function to call when this ObservableSource emits an item and the other ObservableSource has already - * emitted an item, to generate the item to be emitted by the resulting ObservableSource - * @return an Observable that merges the specified ObservableSource into this ObservableSource by using the - * {@code resultSelector} function only when the source ObservableSource sequence (this instance) emits an - * item + * the function to call when the current {@code Observable} emits an item and the other {@code ObservableSource} has already + * emitted an item, to generate the item to be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} or {@code combiner} is {@code null} * @since 2.0 * @see ReactiveX operators documentation: CombineLatest */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable withLatestFrom(@NonNull ObservableSource other, @NonNull BiFunction combiner) { + public final <@NonNull U, @NonNull R> Observable withLatestFrom(@NonNull ObservableSource other, @NonNull BiFunction combiner) { Objects.requireNonNull(other, "other is null"); Objects.requireNonNull(combiner, "combiner is null"); @@ -15553,15 +16407,17 @@ public final Observable withLatestFrom(@NonNull ObservableSourceNote that this operator doesn't emit anything until all other sources have produced at - * least one value. The resulting emission only happens when this ObservableSource emits (and - * not when any of the other sources emit, unlike combineLatest). + * least one value. The resulting emission only happens when the current {@code Observable} emits (and + * not when any of the other sources emit, unlike {@code combineLatest}). * If a source doesn't produce any value and just completes, the sequence is completed immediately. + * If the upstream completes before all other sources have produced at least one value, the sequence completes + * without emission. *

- * + * *

*
Scheduler:
*
This operator does not operate by default on a particular {@link Scheduler}.
@@ -15570,16 +16426,17 @@ public final Observable withLatestFrom(@NonNull ObservableSource the first other source's value type * @param the second other source's value type * @param the result value type - * @param source1 the first other ObservableSource - * @param source2 the second other ObservableSource - * @param combiner the function called with an array of values from each participating ObservableSource - * @return the new ObservableSource instance + * @param source1 the first other {@code ObservableSource} + * @param source2 the second other {@code ObservableSource} + * @param combiner the function called with an array of values from each participating {@code ObservableSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code combiner} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable withLatestFrom( + public final <@NonNull T1, @NonNull T2, @NonNull R> Observable withLatestFrom( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull Function3 combiner) { Objects.requireNonNull(source1, "source1 is null"); @@ -15590,15 +16447,17 @@ public final Observable withLatestFrom( } /** - * Combines the value emission from this ObservableSource with the latest emissions from the - * other ObservableSources via a function to produce the output item. + * Combines the value emission from the current {@code Observable} with the latest emissions from the + * other {@link ObservableSource}s via a function to produce the output item. * *

Note that this operator doesn't emit anything until all other sources have produced at - * least one value. The resulting emission only happens when this ObservableSource emits (and + * least one value. The resulting emission only happens when the current {@code Observable} emits (and * not when any of the other sources emit, unlike combineLatest). * If a source doesn't produce any value and just completes, the sequence is completed immediately. + * If the upstream completes before all other sources have produced at least one value, the sequence completes + * without emission. *

- * + * *

*
Scheduler:
*
This operator does not operate by default on a particular {@link Scheduler}.
@@ -15608,17 +16467,18 @@ public final Observable withLatestFrom( * @param the second other source's value type * @param the third other source's value type * @param the result value type - * @param source1 the first other ObservableSource - * @param source2 the second other ObservableSource - * @param source3 the third other ObservableSource - * @param combiner the function called with an array of values from each participating ObservableSource - * @return the new ObservableSource instance + * @param source1 the first other {@code ObservableSource} + * @param source2 the second other {@code ObservableSource} + * @param source3 the third other {@code ObservableSource} + * @param combiner the function called with an array of values from each participating {@code ObservableSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code combiner} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable withLatestFrom( + public final <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull R> Observable withLatestFrom( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull Function4 combiner) { @@ -15631,15 +16491,17 @@ public final Observable withLatestFrom( } /** - * Combines the value emission from this ObservableSource with the latest emissions from the - * other ObservableSources via a function to produce the output item. + * Combines the value emission from the current {@code Observable} with the latest emissions from the + * other {@link ObservableSource}s via a function to produce the output item. * *

Note that this operator doesn't emit anything until all other sources have produced at - * least one value. The resulting emission only happens when this ObservableSource emits (and + * least one value. The resulting emission only happens when the current {@code Observable} emits (and * not when any of the other sources emit, unlike combineLatest). * If a source doesn't produce any value and just completes, the sequence is completed immediately. + * If the upstream completes before all other sources have produced at least one value, the sequence completes + * without emission. *

- * + * *

*
Scheduler:
*
This operator does not operate by default on a particular {@link Scheduler}.
@@ -15650,18 +16512,20 @@ public final Observable withLatestFrom( * @param the third other source's value type * @param the fourth other source's value type * @param the result value type - * @param source1 the first other ObservableSource - * @param source2 the second other ObservableSource - * @param source3 the third other ObservableSource - * @param source4 the fourth other ObservableSource - * @param combiner the function called with an array of values from each participating ObservableSource - * @return the new ObservableSource instance + * @param source1 the first other {@code ObservableSource} + * @param source2 the second other {@code ObservableSource} + * @param source3 the third other {@code ObservableSource} + * @param source4 the fourth other {@code ObservableSource} + * @param combiner the function called with an array of values from each participating {@code ObservableSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, + * {@code source4} or {@code combiner} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable withLatestFrom( + public final <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull R> Observable withLatestFrom( @NonNull ObservableSource source1, @NonNull ObservableSource source2, @NonNull ObservableSource source3, @NonNull ObservableSource source4, @NonNull Function5 combiner) { @@ -15675,15 +16539,17 @@ public final Observable withLatestFrom( } /** - * Combines the value emission from this ObservableSource with the latest emissions from the - * other ObservableSources via a function to produce the output item. + * Combines the value emission from the current {@code Observable} with the latest emissions from the + * other {@link ObservableSource}s via a function to produce the output item. * *

Note that this operator doesn't emit anything until all other sources have produced at - * least one value. The resulting emission only happens when this ObservableSource emits (and + * least one value. The resulting emission only happens when the current {@code Observable} emits (and * not when any of the other sources emit, unlike combineLatest). * If a source doesn't produce any value and just completes, the sequence is completed immediately. + * If the upstream completes before all other sources have produced at least one value, the sequence completes + * without emission. *

- * + * *

*
Scheduler:
*
This operator does not operate by default on a particular {@link Scheduler}.
@@ -15691,29 +16557,32 @@ public final Observable withLatestFrom( * * @param the result value type * @param others the array of other sources - * @param combiner the function called with an array of values from each participating ObservableSource - * @return the new ObservableSource instance + * @param combiner the function called with an array of values from each participating {@code ObservableSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code others} or {@code combiner} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable withLatestFrom(@NonNull ObservableSource[] others, @NonNull Function combiner) { + public final <@NonNull R> Observable withLatestFrom(@NonNull ObservableSource[] others, @NonNull Function combiner) { Objects.requireNonNull(others, "others is null"); Objects.requireNonNull(combiner, "combiner is null"); return RxJavaPlugins.onAssembly(new ObservableWithLatestFromMany<>(this, others, combiner)); } /** - * Combines the value emission from this ObservableSource with the latest emissions from the - * other ObservableSources via a function to produce the output item. + * Combines the value emission from the current {@code Observable} with the latest emissions from the + * other {@link ObservableSource}s via a function to produce the output item. * *

Note that this operator doesn't emit anything until all other sources have produced at - * least one value. The resulting emission only happens when this ObservableSource emits (and - * not when any of the other sources emit, unlike combineLatest). + * least one value. The resulting emission only happens when the current {@code Observable} emits (and + * not when any of the other sources emit, unlike {@code combineLatest}). * If a source doesn't produce any value and just completes, the sequence is completed immediately. + * If the upstream completes before all other sources have produced at least one value, the sequence completes + * without emission. *

- * + * *

*
Scheduler:
*
This operator does not operate by default on a particular {@link Scheduler}.
@@ -15721,26 +16590,27 @@ public final Observable withLatestFrom(@NonNull ObservableSource[] oth * * @param the result value type * @param others the iterable of other sources - * @param combiner the function called with an array of values from each participating ObservableSource - * @return the new ObservableSource instance + * @param combiner the function called with an array of values from each participating {@code ObservableSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code others} or {@code combiner} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable withLatestFrom(@NonNull Iterable> others, @NonNull Function combiner) { + public final <@NonNull R> Observable withLatestFrom(@NonNull Iterable<@NonNull ? extends ObservableSource> others, @NonNull Function combiner) { Objects.requireNonNull(others, "others is null"); Objects.requireNonNull(combiner, "combiner is null"); return RxJavaPlugins.onAssembly(new ObservableWithLatestFromMany<>(this, others, combiner)); } /** - * Returns an Observable that emits items that are the result of applying a specified function to pairs of - * values, one each from the source ObservableSource and a specified Iterable sequence. + * Returns an {@code Observable} that emits items that are the result of applying a specified function to pairs of + * values, one each from the current {@code Observable} and a specified {@link Iterable} sequence. *

- * + * *

- * Note that the {@code other} Iterable is evaluated as items are observed from the source ObservableSource; it is + * Note that the {@code other} {@code Iterable} is evaluated as items are observed from the current {@code Observable}; it is * not pre-consumed. This allows you to zip infinite streams on either side. *

*
Scheduler:
@@ -15748,32 +16618,32 @@ public final Observable withLatestFrom(@NonNull Iterable * * @param - * the type of items in the {@code other} Iterable + * the type of items in the {@code other} {@code Iterable} * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param other - * the Iterable sequence + * the {@code Iterable} sequence * @param zipper - * a function that combines the pairs of items from the ObservableSource and the Iterable to generate - * the items to be emitted by the resulting ObservableSource - * @return an Observable that pairs up values from the source ObservableSource and the {@code other} Iterable - * sequence and emits the results of {@code zipFunction} applied to these pairs + * a function that combines the pairs of items from the current {@code Observable} and the {@code Iterable} to generate + * the items to be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable zipWith(@NonNull Iterable other, @NonNull BiFunction zipper) { + public final <@NonNull U, @NonNull R> Observable zipWith(@NonNull Iterable other, @NonNull BiFunction zipper) { Objects.requireNonNull(other, "other is null"); Objects.requireNonNull(zipper, "zipper is null"); return RxJavaPlugins.onAssembly(new ObservableZipIterable<>(this, other, zipper)); } /** - * Returns an Observable that emits items that are the result of applying a specified function to pairs of - * values, one each from the source ObservableSource and another specified ObservableSource. + * Returns an {@code Observable} that emits items that are the result of applying a specified function to pairs of + * values, one each from the current {@code Observable} and another specified {@link ObservableSource}. *

- * + * *

* The operator subscribes to its sources in order they are specified and completes eagerly if * one of the sources is shorter than the rest while disposing the other sources. Therefore, it @@ -15792,32 +16662,32 @@ public final Observable zipWith(@NonNull Iterable other, @NonNull B *

* * @param - * the type of items emitted by the {@code other} ObservableSource + * the type of items emitted by the {@code other} {@code ObservableSource} * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param other - * the other ObservableSource + * the other {@code ObservableSource} * @param zipper - * a function that combines the pairs of items from the two ObservableSources to generate the items to - * be emitted by the resulting ObservableSource - * @return an Observable that pairs up values from the source ObservableSource and the {@code other} ObservableSource - * and emits the results of {@code zipFunction} applied to these pairs + * a function that combines the pairs of items from the current {@code Observable} and the other {@code ObservableSource} to generate the items to + * be emitted by the resulting {@code Observable} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable zipWith(@NonNull ObservableSource other, + public final <@NonNull U, @NonNull R> Observable zipWith(@NonNull ObservableSource other, @NonNull BiFunction zipper) { Objects.requireNonNull(other, "other is null"); return zip(this, other, zipper); } /** - * Returns an Observable that emits items that are the result of applying a specified function to pairs of - * values, one each from the source ObservableSource and another specified ObservableSource. + * Returns an {@code Observable} that emits items that are the result of applying a specified function to pairs of + * values, one each from the current {@code Observable} and another specified {@link ObservableSource}. *

- * + * *

* The operator subscribes to its sources in order they are specified and completes eagerly if * one of the sources is shorter than the rest while disposing the other sources. Therefore, it @@ -15836,34 +16706,34 @@ public final Observable zipWith(@NonNull ObservableSource *

* * @param - * the type of items emitted by the {@code other} ObservableSource + * the type of items emitted by the {@code other} {@code ObservableSource} * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param other - * the other ObservableSource + * the other {@code ObservableSource} * @param zipper - * a function that combines the pairs of items from the two ObservableSources to generate the items to - * be emitted by the resulting ObservableSource + * a function that combines the pairs of items from the current {@code Observable} and the other {@code ObservableSource} to generate the items to + * be emitted by the resulting {@code Observable} * @param delayError - * if true, errors from the current Observable or the other ObservableSource is delayed until both terminate - * @return an Observable that pairs up values from the source ObservableSource and the {@code other} ObservableSource - * and emits the results of {@code zipFunction} applied to these pairs + * if {@code true}, errors from the current {@code Observable} or the other {@code ObservableSource} is delayed until both terminate + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable zipWith(@NonNull ObservableSource other, + public final <@NonNull U, @NonNull R> Observable zipWith(@NonNull ObservableSource other, @NonNull BiFunction zipper, boolean delayError) { return zip(this, other, zipper, delayError); } /** - * Returns an Observable that emits items that are the result of applying a specified function to pairs of - * values, one each from the source ObservableSource and another specified ObservableSource. + * Returns an {@code Observable} that emits items that are the result of applying a specified function to pairs of + * values, one each from the current {@code Observable} and another specified {@link ObservableSource}. *

- * + * *

* The operator subscribes to its sources in order they are specified and completes eagerly if * one of the sources is shorter than the rest while disposing the other sources. Therefore, it @@ -15882,27 +16752,28 @@ public final Observable zipWith(@NonNull ObservableSource *

* * @param - * the type of items emitted by the {@code other} ObservableSource + * the type of items emitted by the {@code other} {@code ObservableSource} * @param - * the type of items emitted by the resulting ObservableSource + * the type of items emitted by the resulting {@code Observable} * @param other - * the other ObservableSource + * the other {@code ObservableSource} * @param zipper - * a function that combines the pairs of items from the two ObservableSources to generate the items to - * be emitted by the resulting ObservableSource + * a function that combines the pairs of items from the current {@code Observable} and the other {@code ObservableSource} to generate the items to + * be emitted by the resulting {@code Observable} * @param bufferSize * the capacity hint for the buffer in the inner windows * @param delayError - * if true, errors from the current Observable or the other ObservableSource is delayed until both terminate - * @return an Observable that pairs up values from the source ObservableSource and the {@code other} ObservableSource - * and emits the results of {@code zipFunction} applied to these pairs + * if {@code true}, errors from the current {@code Observable} or the other {@code ObservableSource} is delayed until both terminate + * @return the new {@code Observable} instance * @see ReactiveX operators documentation: Zip + * @throws NullPointerException if {@code other} or {@code zipper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable zipWith(@NonNull ObservableSource other, + public final <@NonNull U, @NonNull R> Observable zipWith(@NonNull ObservableSource other, @NonNull BiFunction zipper, boolean delayError, int bufferSize) { return zip(this, other, zipper, delayError, bufferSize); } @@ -15911,13 +16782,12 @@ public final Observable zipWith(@NonNull ObservableSource // Fluent test support, super handy and reduces test preparation boilerplate // ------------------------------------------------------------------------- /** - * Creates a TestObserver and subscribes - * it to this Observable. + * Creates a {@link TestObserver} and subscribes it to the current {@code Observable}. *
*
Scheduler:
*
{@code test} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new TestObserver instance + * @return the new {@code TestObserver} instance * @since 2.0 */ @CheckReturnValue @@ -15930,15 +16800,16 @@ public final TestObserver test() { // NoPMD } /** - * Creates a TestObserver, optionally disposes it and then subscribes - * it to this Observable. + * Creates a {@link TestObserver}, optionally disposes it and then subscribes + * it to the current {@code Observable}. * *
*
Scheduler:
*
{@code test} does not operate by default on a particular {@link Scheduler}.
*
- * @param dispose dispose the TestObserver before it is subscribed to this Observable? - * @return the new TestObserver instance + * @param dispose indicates if the {@code TestObserver} should be disposed before + * it is subscribed to the current {@code Observable} + * @return the new {@code TestObserver} instance * @since 2.0 */ @CheckReturnValue @@ -15975,7 +16846,8 @@ public final TestObserver test(boolean dispose) { // NoPMD *
* @param the element type of the optional value * @param optional the optional value to convert into an {@code Observable} - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code optional} is {@code null} * @since 3.0.0 * @see #just(Object) * @see #empty() @@ -15983,7 +16855,7 @@ public final TestObserver test(boolean dispose) { // NoPMD @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable<@NonNull T> fromOptional(@NonNull Optional optional) { + public static <@NonNull T> Observable<@NonNull T> fromOptional(@NonNull Optional optional) { Objects.requireNonNull(optional, "optional is null"); return optional.map(Observable::just).orElseGet(Observable::empty); } @@ -15994,7 +16866,7 @@ public final TestObserver test(boolean dispose) { // NoPMD * *

* Note that the operator takes an already instantiated, running or terminated {@code CompletionStage}. - * If the optional is to be created per consumer upon subscription, use {@link #defer(Supplier)} + * If the {@code CompletionStage} is to be created per consumer upon subscription, use {@link #defer(Supplier)} * around {@code fromCompletionStage}: *


      * Observable.defer(() -> Observable.fromCompletionStage(createCompletionStage()));
@@ -16008,15 +16880,16 @@ public final TestObserver test(boolean dispose) { // NoPMD
      *  
Scheduler:
*
{@code fromCompletionStage} does not operate by default on a particular {@link Scheduler}.
*
- * @param the element type of the CompletionStage - * @param stage the CompletionStage to convert to Observable and signal its terminal value or error - * @return the new Observable instance + * @param the element type of the {@code CompletionStage} + * @param stage the {@code CompletionStage} to convert to {@code Observable} and signal its terminal value or error + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code stage} is {@code null} * @since 3.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable<@NonNull T> fromCompletionStage(@NonNull CompletionStage stage) { + public static <@NonNull T> Observable<@NonNull T> fromCompletionStage(@NonNull CompletionStage stage) { Objects.requireNonNull(stage, "stage is null"); return RxJavaPlugins.onAssembly(new ObservableFromCompletionStage<>(stage)); } @@ -16026,7 +16899,7 @@ public final TestObserver test(boolean dispose) { // NoPMD *

* *

- * The operator closes the {@code Stream} upon cancellation and when it terminates. Exceptions raised when + * The operator closes the {@code Stream} upon cancellation and when it terminates. The exceptions raised when * closing a {@code Stream} are routed to the global error handler ({@link RxJavaPlugins#onError(Throwable)}. * If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #fromIterable(Iterable)}: *


@@ -16051,14 +16924,15 @@ public final TestObserver test(boolean dispose) { // NoPMD
      * 
* @param the element type of the source {@code Stream} * @param stream the {@code Stream} of values to emit - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code stream} is {@code null} * @since 3.0.0 * @see #fromIterable(Iterable) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Observable<@NonNull T> fromStream(@NonNull Stream stream) { + public static <@NonNull T> Observable<@NonNull T> fromStream(@NonNull Stream stream) { Objects.requireNonNull(stream, "stream is null"); return RxJavaPlugins.onAssembly(new ObservableFromStream<>(stream)); } @@ -16072,10 +16946,11 @@ public final TestObserver test(boolean dispose) { // NoPMD *
Scheduler:
*
{@code mapOptional} does not operate by default on a particular {@link Scheduler}.
*
- * @param the non-null output type + * @param the non-{@code null} output type * @param mapper the function that receives the upstream item and should return a non-empty {@code Optional} * to emit as the output or an empty {@code Optional} to skip to the next upstream value - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @since 3.0.0 * @see #map(Function) * @see #filter(Predicate) @@ -16089,8 +16964,8 @@ public final TestObserver test(boolean dispose) { // NoPMD } /** - * Collects the finite upstream's values into a container via a Stream {@link Collector} callback set and emits - * it as the success result. + * Collects the finite upstream's values into a container via a {@link Stream} {@link Collector} callback set and emits + * it as the success result as a {@link Single}. *

* * @@ -16098,11 +16973,12 @@ public final TestObserver test(boolean dispose) { // NoPMD *

Scheduler:
*
{@code collect} does not operate by default on a particular {@link Scheduler}.
*
- * @param the non-null result type + * @param the non-{@code null} result type * @param the intermediate container type used for the accumulation * @param collector the interface defining the container supplier, accumulator and finisher functions; * see {@link Collectors} for some standard implementations - * @return the new Single instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code collector} is {@code null} * @since 3.0.0 * @see Collectors * @see #collect(Supplier, BiConsumer) @@ -16110,7 +16986,7 @@ public final TestObserver test(boolean dispose) { // NoPMD @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final <@NonNull R, A> Single collect(@NonNull Collector collector) { + public final <@NonNull R, @Nullable A> Single collect(@NonNull Collector collector) { Objects.requireNonNull(collector, "collector is null"); return RxJavaPlugins.onAssembly(new ObservableCollectWithCollectorSingle<>(this, collector)); } @@ -16137,7 +17013,8 @@ public final TestObserver test(boolean dispose) { // NoPMD *
{@code firstStage} does not operate by default on a particular {@link Scheduler}.
*
* @param defaultItem the item to signal if the upstream is empty - * @return the new CompletionStage instance + * @return the new {@code CompletionStage} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @since 3.0.0 * @see #firstOrErrorStage() */ @@ -16171,7 +17048,8 @@ public final CompletionStage firstStage(@Nullable T defaultItem) { *
{@code singleStage} does not operate by default on a particular {@link Scheduler}.
*
* @param defaultItem the item to signal if the upstream is empty - * @return the new CompletionStage instance + * @return the new {@code CompletionStage} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @since 3.0.0 * @see #singleOrErrorStage() */ @@ -16204,7 +17082,8 @@ public final CompletionStage singleStage(@Nullable T defaultItem) { *
{@code lastStage} does not operate by default on a particular {@link Scheduler}.
*
* @param defaultItem the item to signal if the upstream is empty - * @return the new CompletionStage instance + * @return the new {@code CompletionStage} instance + * @throws NullPointerException if {@code defaultItem} is {@code null} * @since 3.0.0 * @see #lastOrErrorStage() */ @@ -16230,7 +17109,7 @@ public final CompletionStage lastStage(@Nullable T defaultItem) { *
Scheduler:
*
{@code firstOrErrorStage} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new CompletionStage instance + * @return the new {@code CompletionStage} instance * @since 3.0.0 * @see #firstStage(Object) */ @@ -16257,7 +17136,7 @@ public final CompletionStage firstOrErrorStage() { *
Scheduler:
*
{@code singleOrErrorStage} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new CompletionStage instance + * @return the new {@code CompletionStage} instance * @since 3.0.0 * @see #singleStage(Object) */ @@ -16283,7 +17162,7 @@ public final CompletionStage singleOrErrorStage() { *
Scheduler:
*
{@code lastOrErrorStage} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new CompletionStage instance + * @return the new {@code CompletionStage} instance * @since 3.0.0 * @see #lastStage(Object) */ @@ -16295,7 +17174,7 @@ public final CompletionStage lastOrErrorStage() { } /** - * Creates a sequential {@link Stream} to consume or process this {@code Observable} in a blocking manner via + * Creates a sequential {@link Stream} to consume or process the current {@code Observable} in a blocking manner via * the Java {@code Stream} API. *

* @@ -16315,7 +17194,7 @@ public final CompletionStage lastOrErrorStage() { *

{@code blockingStream} does not operate by default on a particular {@link Scheduler}.
*
* - * @return the new Stream instance + * @return the new {@code Stream} instance * @since 3.0.0 * @see #blockingStream(int) */ @@ -16327,7 +17206,7 @@ public final Stream blockingStream() { } /** - * Creates a sequential {@link Stream} to consume or process this {@code Observable} in a blocking manner via + * Creates a sequential {@link Stream} to consume or process the current {@code Observable} in a blocking manner via * the Java {@code Stream} API. *

* @@ -16348,7 +17227,8 @@ public final Stream blockingStream() { *

* * @param capacityHint the expected number of items to be buffered - * @return the new Stream instance + * @return the new {@code Stream} instance + * @throws IllegalArgumentException if {@code capacityHint} is non-positive * @since 3.0.0 */ @CheckReturnValue @@ -16365,11 +17245,11 @@ public final Stream blockingStream(int capacityHint) { *

* *

- * Due to the blocking and sequential nature of Java {@link Stream}s, the streams are mapped and consumed in a sequential fashion + * Due to the blocking and sequential nature of Java {@code Stream}s, the streams are mapped and consumed in a sequential fashion * without interleaving (unlike a more general {@link #flatMap(Function)}). Therefore, {@code flatMapStream} and * {@code concatMapStream} are identical operators and are provided as aliases. *

- * The operator closes the {@code Stream} upon cancellation and when it terminates. Exceptions raised when + * The operator closes the {@code Stream} upon cancellation and when it terminates. The exceptions raised when * closing a {@code Stream} are routed to the global error handler ({@link RxJavaPlugins#onError(Throwable)}. * If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #concatMapIterable(Function)}: *


@@ -16394,8 +17274,9 @@ public final Stream blockingStream(int capacityHint) {
      * @param  the element type of the {@code Stream}s and the result
      * @param mapper the function that receives an upstream item and should return a {@code Stream} whose elements
      * will be emitted to the downstream
-     * @return the new Observable instance
+     * @return the new {@code Observable} instance
      * @since 3.0.0
+     * @throws NullPointerException if {@code mapper} is {@code null}
      * @see #concatMap(Function)
      * @see #concatMapIterable(Function)
      * @see #flatMapStream(Function)
@@ -16412,11 +17293,11 @@ public final Stream blockingStream(int capacityHint) {
      * 

* *

- * Due to the blocking and sequential nature of Java {@link Stream}s, the streams are mapped and consumed in a sequential fashion + * Due to the blocking and sequential nature of Java {@code Stream}s, the streams are mapped and consumed in a sequential fashion * without interleaving (unlike a more general {@link #flatMap(Function)}). Therefore, {@code flatMapStream} and * {@code concatMapStream} are identical operators and are provided as aliases. *

- * The operator closes the {@code Stream} upon cancellation and when it terminates. Exceptions raised when + * The operator closes the {@code Stream} upon cancellation and when it terminates. The exceptions raised when * closing a {@code Stream} are routed to the global error handler ({@link RxJavaPlugins#onError(Throwable)}. * If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #flatMapIterable(Function)}: *


@@ -16441,8 +17322,9 @@ public final Stream blockingStream(int capacityHint) {
      * @param  the element type of the {@code Stream}s and the result
      * @param mapper the function that receives an upstream item and should return a {@code Stream} whose elements
      * will be emitted to the downstream
-     * @return the new Observable instance
+     * @return the new {@code Observable} instance
      * @since 3.0.0
+     * @throws NullPointerException if {@code mapper} is {@code null}
      * @see #flatMap(Function)
      * @see #flatMapIterable(Function)
      */
diff --git a/src/main/java/io/reactivex/rxjava3/core/ObservableConverter.java b/src/main/java/io/reactivex/rxjava3/core/ObservableConverter.java
index acdde63b290..24cb2c9fad1 100644
--- a/src/main/java/io/reactivex/rxjava3/core/ObservableConverter.java
+++ b/src/main/java/io/reactivex/rxjava3/core/ObservableConverter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -24,13 +24,12 @@
  * @since 2.2
  */
 @FunctionalInterface
-public interface ObservableConverter {
+public interface ObservableConverter<@NonNull T, @NonNull R> {
     /**
      * Applies a function to the upstream {@link Observable} and returns a converted value of type {@code R}.
      *
      * @param upstream the upstream {@code Observable} instance
      * @return the converted value
      */
-    @NonNull
     R apply(@NonNull Observable upstream);
 }
diff --git a/src/main/java/io/reactivex/rxjava3/core/ObservableEmitter.java b/src/main/java/io/reactivex/rxjava3/core/ObservableEmitter.java
index 776d6963d90..0658c4ba818 100644
--- a/src/main/java/io/reactivex/rxjava3/core/ObservableEmitter.java
+++ b/src/main/java/io/reactivex/rxjava3/core/ObservableEmitter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -15,7 +15,7 @@
 
 import io.reactivex.rxjava3.annotations.*;
 import io.reactivex.rxjava3.disposables.Disposable;
-import io.reactivex.rxjava3.functions.Cancellable;
+import io.reactivex.rxjava3.functions.*;
 
 /**
  * Abstraction over an RxJava {@link Observer} that allows associating
@@ -47,7 +47,7 @@
  *
  * @param  the value type to emit
  */
-public interface ObservableEmitter extends Emitter {
+public interface ObservableEmitter<@NonNull T> extends Emitter {
 
     /**
      * Sets a {@link Disposable} on this emitter; any previous {@code Disposable}
diff --git a/src/main/java/io/reactivex/rxjava3/core/ObservableOnSubscribe.java b/src/main/java/io/reactivex/rxjava3/core/ObservableOnSubscribe.java
index bcde496462d..056441620ad 100644
--- a/src/main/java/io/reactivex/rxjava3/core/ObservableOnSubscribe.java
+++ b/src/main/java/io/reactivex/rxjava3/core/ObservableOnSubscribe.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -10,19 +10,20 @@
  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
  * the License for the specific language governing permissions and limitations under the License.
  */
+
 package io.reactivex.rxjava3.core;
 
 import io.reactivex.rxjava3.annotations.NonNull;
 
 /**
  * A functional interface that has a {@code subscribe()} method that receives
- * an instance of an {@link ObservableEmitter} instance that allows pushing
+ * an {@link ObservableEmitter} instance that allows pushing
  * events in a cancellation-safe manner.
  *
  * @param  the value type pushed
  */
 @FunctionalInterface
-public interface ObservableOnSubscribe {
+public interface ObservableOnSubscribe<@NonNull T> {
 
     /**
      * Called for each {@link Observer} that subscribes.
diff --git a/src/main/java/io/reactivex/rxjava3/core/ObservableOperator.java b/src/main/java/io/reactivex/rxjava3/core/ObservableOperator.java
index ff9dbc58529..fd697fa626e 100644
--- a/src/main/java/io/reactivex/rxjava3/core/ObservableOperator.java
+++ b/src/main/java/io/reactivex/rxjava3/core/ObservableOperator.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -22,7 +22,7 @@
  * @param  the value type of the upstream
  */
 @FunctionalInterface
-public interface ObservableOperator {
+public interface ObservableOperator<@NonNull Downstream, @NonNull Upstream> {
     /**
      * Applies a function to the child {@link Observer} and returns a new parent {@code Observer}.
      * @param observer the child {@code Observer} instance
diff --git a/src/main/java/io/reactivex/rxjava3/core/ObservableSource.java b/src/main/java/io/reactivex/rxjava3/core/ObservableSource.java
index c2309e5b8d0..c00bfc2170a 100644
--- a/src/main/java/io/reactivex/rxjava3/core/ObservableSource.java
+++ b/src/main/java/io/reactivex/rxjava3/core/ObservableSource.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -10,6 +10,7 @@
  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
  * the License for the specific language governing permissions and limitations under the License.
  */
+
 package io.reactivex.rxjava3.core;
 
 import io.reactivex.rxjava3.annotations.NonNull;
@@ -22,7 +23,7 @@
  * @since 2.0
  */
 @FunctionalInterface
-public interface ObservableSource {
+public interface ObservableSource<@NonNull T> {
 
     /**
      * Subscribes the given {@link Observer} to this {@link ObservableSource} instance.
diff --git a/src/main/java/io/reactivex/rxjava3/core/ObservableTransformer.java b/src/main/java/io/reactivex/rxjava3/core/ObservableTransformer.java
index 18ce5e02c9f..57b32bdc71f 100644
--- a/src/main/java/io/reactivex/rxjava3/core/ObservableTransformer.java
+++ b/src/main/java/io/reactivex/rxjava3/core/ObservableTransformer.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -22,7 +22,7 @@
  * @param  the downstream value type
  */
 @FunctionalInterface
-public interface ObservableTransformer {
+public interface ObservableTransformer<@NonNull Upstream, @NonNull Downstream> {
     /**
      * Applies a function to the upstream {@link Observable} and returns an {@link ObservableSource} with
      * optionally different element type.
diff --git a/src/main/java/io/reactivex/rxjava3/core/Observer.java b/src/main/java/io/reactivex/rxjava3/core/Observer.java
index de02f8ac88a..6b911f51e58 100644
--- a/src/main/java/io/reactivex/rxjava3/core/Observer.java
+++ b/src/main/java/io/reactivex/rxjava3/core/Observer.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -73,7 +73,7 @@
  * @param 
  *          the type of item the Observer expects to observe
  */
-public interface Observer {
+public interface Observer<@NonNull T> {
 
     /**
      * Provides the {@link Observer} with the means of cancelling (disposing) the
diff --git a/src/main/java/io/reactivex/rxjava3/core/Scheduler.java b/src/main/java/io/reactivex/rxjava3/core/Scheduler.java
index 80eda093c44..3aa001127ad 100644
--- a/src/main/java/io/reactivex/rxjava3/core/Scheduler.java
+++ b/src/main/java/io/reactivex/rxjava3/core/Scheduler.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -13,15 +13,14 @@
 
 package io.reactivex.rxjava3.core;
 
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
 import io.reactivex.rxjava3.annotations.*;
 import io.reactivex.rxjava3.disposables.Disposable;
-import io.reactivex.rxjava3.exceptions.Exceptions;
 import io.reactivex.rxjava3.functions.Function;
 import io.reactivex.rxjava3.internal.disposables.*;
 import io.reactivex.rxjava3.internal.schedulers.*;
-import io.reactivex.rxjava3.internal.util.ExceptionHelper;
 import io.reactivex.rxjava3.plugins.RxJavaPlugins;
 import io.reactivex.rxjava3.schedulers.SchedulerRunnableIntrospection;
 
@@ -61,8 +60,9 @@
  * interface which can grant access to the original or hooked {@code Runnable}, thus, a repeated {@code RxJavaPlugins.onSchedule}
  * can detect the earlier hook and not apply a new one over again.
  * 

- * The default implementation of {@link #now(TimeUnit)} and {@link Worker#now(TimeUnit)} methods to return current - * {@link System#currentTimeMillis()} value in the desired time unit. Custom {@code Scheduler} implementations can override this + * The default implementation of {@link #now(TimeUnit)} and {@link Worker#now(TimeUnit)} methods to return current {@link System#currentTimeMillis()} + * value in the desired time unit, unless {@code rx3.scheduler.use-nanotime} (boolean) is set. When the property is set to + * {@code true}, the method uses {@link System#nanoTime()} as its basis instead. Custom {@code Scheduler} implementations can override this * to provide specialized time accounting (such as virtual time to be advanced programmatically). * Note that operators requiring a {@code Scheduler} may rely on either of the {@code now()} calls provided by * {@code Scheduler} or {@code Worker} respectively, therefore, it is recommended they represent a logically @@ -74,8 +74,8 @@ * based on the relative time between it and {@link Worker#now(TimeUnit)}. However, drifts or changes in the * system clock could affect this calculation either by scheduling subsequent runs too frequently or too far apart. * Therefore, the default implementation uses the {@link #clockDriftTolerance()} value (set via - * {@code rx3.scheduler.drift-tolerance} in minutes) to detect a drift in {@link Worker#now(TimeUnit)} and - * re-adjust the absolute/relative time calculation accordingly. + * {@code rx3.scheduler.drift-tolerance} and {@code rx3.scheduler.drift-tolerance-unit}) to detect a + * drift in {@link Worker#now(TimeUnit)} and re-adjust the absolute/relative time calculation accordingly. *

* The default implementations of {@link #start()} and {@link #shutdown()} do nothing and should be overridden if the * underlying task-execution scheme supports stopping and restarting itself. @@ -89,20 +89,73 @@ * All methods on the {@code Scheduler} and {@code Worker} classes should be thread safe. */ public abstract class Scheduler { + /** + * Value representing whether to use {@link System#nanoTime()}, or default as clock for {@link #now(TimeUnit)} + * and {@link Scheduler.Worker#now(TimeUnit)}. + *

+ * Associated system parameter: + *

    + *
  • {@code rx3.scheduler.use-nanotime}, boolean, default {@code false} + *
+ */ + static boolean IS_DRIFT_USE_NANOTIME = Boolean.getBoolean("rx3.scheduler.use-nanotime"); + + /** + * Returns the current clock time depending on state of {@link Scheduler#IS_DRIFT_USE_NANOTIME} in given {@code unit} + *

+ * By default {@link System#currentTimeMillis()} will be used as the clock. When the property is set + * {@link System#nanoTime()} will be used. + *

+ * @param unit the time unit + * @return the 'current time' in given unit + * @throws NullPointerException if {@code unit} is {@code null} + */ + static long computeNow(TimeUnit unit) { + if (!IS_DRIFT_USE_NANOTIME) { + return unit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } + return unit.convert(System.nanoTime(), TimeUnit.NANOSECONDS); + } + /** * The tolerance for a clock drift in nanoseconds where the periodic scheduler will rebase. *

- * The associated system parameter, {@code rx3.scheduler.drift-tolerance}, expects its value in minutes. + * Associated system parameters: + *

    + *
  • {@code rx3.scheduler.drift-tolerance}, long, default {@code 15}
  • + *
  • {@code rx3.scheduler.drift-tolerance-unit}, string, default {@code minutes}, + * supports {@code seconds} and {@code milliseconds}. + *
+ */ + static final long CLOCK_DRIFT_TOLERANCE_NANOSECONDS = + computeClockDrift( + Long.getLong("rx3.scheduler.drift-tolerance", 15), + System.getProperty("rx3.scheduler.drift-tolerance-unit", "minutes") + ); + + /** + * Returns the clock drift tolerance in nanoseconds based on the input selection. + * @param time the time value + * @param timeUnit the time unit string + * @return the time amount in nanoseconds */ - static final long CLOCK_DRIFT_TOLERANCE_NANOSECONDS; - static { - CLOCK_DRIFT_TOLERANCE_NANOSECONDS = TimeUnit.MINUTES.toNanos( - Long.getLong("rx3.scheduler.drift-tolerance", 15)); + static long computeClockDrift(long time, String timeUnit) { + if ("seconds".equalsIgnoreCase(timeUnit)) { + return TimeUnit.SECONDS.toNanos(time); + } else if ("milliseconds".equalsIgnoreCase(timeUnit)) { + return TimeUnit.MILLISECONDS.toNanos(time); + } + return TimeUnit.MINUTES.toNanos(time); } /** * Returns the clock drift tolerance in nanoseconds. - *

Related system property: {@code rx3.scheduler.drift-tolerance} in minutes. + *

Related system properties: + *

    + *
  • {@code rx3.scheduler.drift-tolerance}, long, default {@code 15}
  • + *
  • {@code rx3.scheduler.drift-tolerance-unit}, string, default {@code minutes}, + * supports {@code seconds} and {@code milliseconds}. + *
* @return the tolerance in nanoseconds * @since 2.0 */ @@ -128,10 +181,11 @@ public static long clockDriftTolerance() { * Returns the 'current time' of the Scheduler in the specified time unit. * @param unit the time unit * @return the 'current time' + * @throws NullPointerException if {@code unit} is {@code null} * @since 2.0 */ public long now(@NonNull TimeUnit unit) { - return unit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS); + return computeNow(unit); } /** @@ -172,6 +226,7 @@ public void shutdown() { * @param run the task to execute * * @return the Disposable instance that let's one cancel this particular task. + * @throws NullPointerException if {@code run} is {@code null} * @since 2.0 */ @NonNull @@ -190,6 +245,7 @@ public Disposable scheduleDirect(@NonNull Runnable run) { * @param delay the delay amount, non-positive values indicate non-delayed scheduling * @param unit the unit of measure of the delay amount * @return the Disposable that let's one cancel this particular delayed task. + * @throws NullPointerException if {@code run} or {@code unit} is {@code null} * @since 2.0 */ @NonNull @@ -222,6 +278,7 @@ public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull Tim * @param period the period at which the task should be re-executed * @param unit the unit of measure of the delay amount * @return the Disposable that let's one cancel this particular delayed task. + * @throws NullPointerException if {@code run} or {@code unit} is {@code null} * @since 2.0 */ @NonNull @@ -293,7 +350,7 @@ public Disposable schedulePeriodicallyDirect(@NonNull Runnable run, long initial * }); *
* - * Slowing down the rate to no more than than 1 a second. This suffers from + * Slowing down the rate to no more than 1 a second. This suffers from * the same problem as the one above I could find an {@link Flowable} * operator that limits the rate without dropping the values (aka leaky * bucket algorithm). @@ -313,11 +370,13 @@ public Disposable schedulePeriodicallyDirect(@NonNull Runnable run, long initial * @param combine the function that takes a two-level nested Flowable sequence of a Completable and returns * the Completable that will be subscribed to and should trigger the execution of the scheduled Actions. * @return the Scheduler with the customized execution behavior + * @throws NullPointerException if {@code combine} is {@code null} * @since 2.1 */ @SuppressWarnings("unchecked") @NonNull public S when(@NonNull Function>, Completable> combine) { + Objects.requireNonNull(combine, "combine is null"); return (S) new SchedulerWhen(combine, this); } @@ -332,8 +391,9 @@ public S when(@NonNull Function - * The default implementation of the {@link #now(TimeUnit)} method returns current - * {@link System#currentTimeMillis()} value in the desired time unit. Custom {@code Worker} implementations can override this + * The default implementation of the {@link #now(TimeUnit)} method returns current {@link System#currentTimeMillis()} + * value in the desired time unit, unless {@code rx3.scheduler.use-nanotime} (boolean) is set. When the property is set to + * {@code true}, the method uses {@link System#nanoTime()} as its basis instead. Custom {@code Worker} implementations can override this * to provide specialized time accounting (such as virtual time to be advanced programmatically). * Note that operators requiring a scheduler may rely on either of the {@code now()} calls provided by * {@code Scheduler} or {@code Worker} respectively, therefore, it is recommended they represent a logically @@ -345,7 +405,7 @@ public S when(@NonNull Function * If the {@code Worker} is disposed, the {@code schedule} methods @@ -365,6 +425,7 @@ public abstract static class Worker implements Disposable { * @param run * Runnable to schedule * @return a Disposable to be able to unsubscribe the action (cancel it if not executed) + * @throws NullPointerException if {@code run} is {@code null} */ @NonNull public Disposable schedule(@NonNull Runnable run) { @@ -386,6 +447,7 @@ public Disposable schedule(@NonNull Runnable run) { * @param unit * the time unit of {@code delayTime} * @return a Disposable to be able to unsubscribe the action (cancel it if not executed) + * @throws NullPointerException if {@code run} or {@code unit} is {@code null} */ @NonNull public abstract Disposable schedule(@NonNull Runnable run, long delay, @NonNull TimeUnit unit); @@ -417,6 +479,7 @@ public Disposable schedule(@NonNull Runnable run) { * @param unit * the time unit of {@code period} * @return a Disposable to be able to unsubscribe the action (cancel it if not executed) + * @throws NullPointerException if {@code run} or {@code unit} is {@code null} */ @NonNull public Disposable schedulePeriodically(@NonNull Runnable run, final long initialDelay, final long period, @NonNull final TimeUnit unit) { @@ -445,10 +508,11 @@ public Disposable schedulePeriodically(@NonNull Runnable run, final long initial * Returns the 'current time' of the Worker in the specified time unit. * @param unit the time unit * @return the 'current time' + * @throws NullPointerException if {@code unit} is {@code null} * @since 2.0 */ public long now(@NonNull TimeUnit unit) { - return unit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS); + return computeNow(unit); } /** @@ -531,9 +595,10 @@ public void run() { try { run.run(); } catch (Throwable ex) { - Exceptions.throwIfFatal(ex); - worker.dispose(); - throw ExceptionHelper.wrapOrThrow(ex); + // Exceptions.throwIfFatal(ex); nowhere to go + dispose(); + RxJavaPlugins.onError(ex); + throw ex; } } } @@ -575,7 +640,13 @@ static final class DisposeTask implements Disposable, Runnable, SchedulerRunnabl public void run() { runner = Thread.currentThread(); try { - decoratedRun.run(); + try { + decoratedRun.run(); + } catch (Throwable ex) { + // Exceptions.throwIfFatal(e); nowhere to go + RxJavaPlugins.onError(ex); + throw ex; + } } finally { dispose(); runner = null; diff --git a/src/main/java/io/reactivex/rxjava3/core/Single.java b/src/main/java/io/reactivex/rxjava3/core/Single.java index 28177cc9e31..6cf5a3f7890 100644 --- a/src/main/java/io/reactivex/rxjava3/core/Single.java +++ b/src/main/java/io/reactivex/rxjava3/core/Single.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,12 +17,11 @@ import java.util.concurrent.*; import java.util.stream.*; -import org.reactivestreams.Publisher; +import org.reactivestreams.*; import io.reactivex.rxjava3.annotations.*; -import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.*; import io.reactivex.rxjava3.internal.fuseable.*; @@ -31,19 +30,19 @@ import io.reactivex.rxjava3.internal.operators.completable.*; import io.reactivex.rxjava3.internal.operators.flowable.*; import io.reactivex.rxjava3.internal.operators.maybe.*; -import io.reactivex.rxjava3.internal.operators.mixed.SingleFlatMapObservable; -import io.reactivex.rxjava3.internal.operators.observable.*; +import io.reactivex.rxjava3.internal.operators.mixed.*; +import io.reactivex.rxjava3.internal.operators.observable.ObservableSingleSingle; import io.reactivex.rxjava3.internal.operators.single.*; import io.reactivex.rxjava3.internal.util.ErrorMode; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.schedulers.*; /** * The {@code Single} class implements the Reactive Pattern for a single value response. *

* {@code Single} behaves similarly to {@link Observable} except that it can only emit either a single successful - * value or an error (there is no "onComplete" notification as there is for an {@link Observable}). + * value or an error (there is no {@code onComplete} notification as there is for an {@code Observable}). *

* The {@code Single} class implements the {@link SingleSource} base interface and the default consumer * type it interacts with is the {@link SingleObserver} via the {@link #subscribe(SingleObserver)} method. @@ -66,9 +65,9 @@ *

* The documentation for this class makes use of marble diagrams. The following legend explains these diagrams: *

- * + * *

- * See {@link Flowable} or {@link Observable} for the + * See {@link Flowable} or {@code Observable} for the * implementation of the Reactive Pattern for a stream or vector of values. *

* For more information see the ReactiveX @@ -110,40 +109,41 @@ * allow working with a {@code SingleObserver} (or subclass) instance to be applied with in * a fluent manner (such as in the example above). * @param - * the type of the item emitted by the Single + * the type of the item emitted by the {@code Single} * @since 2.0 * @see io.reactivex.rxjava3.observers.DisposableSingleObserver */ -public abstract class Single implements SingleSource { +public abstract class Single<@NonNull T> implements SingleSource { /** - * Runs multiple SingleSources and signals the events of the first one that signals (disposing + * Runs multiple {@link SingleSource}s and signals the events of the first one that signals (disposing * the rest). *

- * + * *

*
Scheduler:
*
{@code amb} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources the Iterable sequence of sources. A subscription to each source will - * occur in the same order as in this Iterable. - * @return the new Single instance + * @param sources the {@link Iterable} sequence of sources. A subscription to each source will + * occur in the same order as in this {@code Iterable}. + * @return the new {@code Single} instance + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single amb(@NonNull Iterable> sources) { + public static <@NonNull T> Single amb(@NonNull Iterable<@NonNull ? extends SingleSource> sources) { Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new SingleAmb<>(null, sources)); } /** - * Runs multiple SingleSources and signals the events of the first one that signals (disposing + * Runs multiple {@link SingleSource}s and signals the events of the first one that signals (disposing * the rest). *

- * + * *

*
Scheduler:
*
{@code ambArray} does not operate by default on a particular {@link Scheduler}.
@@ -151,14 +151,16 @@ public static Single amb(@NonNull Iterable the value type * @param sources the array of sources. A subscription to each source will * occur in the same order as in this array. - * @return the new Single instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs @NonNull - public static Single ambArray(@NonNull SingleSource... sources) { + public static <@NonNull T> Single ambArray(@NonNull SingleSource... sources) { + Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { return error(SingleInternalHelper.emptyThrower()); } @@ -171,110 +173,113 @@ public static Single ambArray(@NonNull SingleSource... sourc } /** - * Concatenate the single values, in a non-overlapping fashion, of the SingleSources provided by - * an Iterable sequence. + * Concatenate the single values, in a non-overlapping fashion, of the {@link SingleSource}s provided by + * an {@link Iterable} sequence. *

- * + * *

*
Backpressure:
- *
The returned {@code Flowable} honors the backpressure of the downstream consumer.
+ *
The returned {@link Flowable} honors the backpressure of the downstream consumer.
*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources the Iterable sequence of SingleSource instances - * @return the new Flowable instance + * @param sources the {@code Iterable} sequence of {@code SingleSource} instances + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.FULL) - public static Flowable concat(@NonNull Iterable> sources) { - return concat(Flowable.fromIterable(sources)); + public static <@NonNull T> Flowable concat(@NonNull Iterable<@NonNull ? extends SingleSource> sources) { + return Flowable.fromIterable(sources).concatMapSingleDelayError(Functions.identity(), false); } /** - * Concatenate the single values, in a non-overlapping fashion, of the SingleSources provided by - * an Observable sequence. + * Concatenate the single values, in a non-overlapping fashion, of the {@link SingleSource}s provided by + * an {@link ObservableSource} sequence. *

- * + * *

*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources the ObservableSource of SingleSource instances - * @return the new Observable instance + * @param sources the {@code ObservableSource} of {@code SingleSource} instances + * @return the new {@link Observable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Observable concat(@NonNull ObservableSource> sources) { + public static <@NonNull T> Observable concat(@NonNull ObservableSource> sources) { Objects.requireNonNull(sources, "sources is null"); - return RxJavaPlugins.onAssembly(new ObservableConcatMap(sources, SingleInternalHelper.toObservable(), 2, ErrorMode.IMMEDIATE)); + return RxJavaPlugins.onAssembly(new ObservableConcatMapSingle<>(sources, Functions.identity(), ErrorMode.IMMEDIATE, 2)); } /** - * Concatenate the single values, in a non-overlapping fashion, of the SingleSources provided by - * a Publisher sequence. + * Concatenate the single values, in a non-overlapping fashion, of the {@link SingleSource}s provided by + * a {@link Publisher} sequence. *

- * + * *

*
Backpressure:
- *
The returned {@code Flowable} honors the backpressure of the downstream consumer + *
The returned {@link Flowable} honors the backpressure of the downstream consumer * and the sources {@code Publisher} is expected to honor it as well.
*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources the Publisher of SingleSource instances - * @return the new Flowable instance + * @param sources the {@code Publisher} of {@code SingleSource} instances + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concat(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable concat(@NonNull Publisher<@NonNull ? extends SingleSource> sources) { return concat(sources, 2); } /** - * Concatenate the single values, in a non-overlapping fashion, of the SingleSources provided by - * a Publisher sequence and prefetched by the specified amount. + * Concatenate the single values, in a non-overlapping fashion, of the {@link SingleSource}s provided by + * a {@link Publisher} sequence and prefetched by the specified amount. *

- * + * *

*
Backpressure:
- *
The returned {@code Flowable} honors the backpressure of the downstream consumer + *
The returned {@link Flowable} honors the backpressure of the downstream consumer * and the sources {@code Publisher} is expected to honor it as well.
*
Scheduler:
*
{@code concat} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources the Publisher of SingleSource instances - * @param prefetch the number of SingleSources to prefetch from the Publisher - * @return the new Flowable instance + * @param sources the {@code Publisher} of {@code SingleSource} instances + * @param prefetch the number of {@code SingleSource}s to prefetch from the {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive * @since 2.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Flowable concat(@NonNull Publisher> sources, int prefetch) { + public static <@NonNull T> Flowable concat(@NonNull Publisher<@NonNull ? extends SingleSource> sources, int prefetch) { Objects.requireNonNull(sources, "sources is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new FlowableConcatMapPublisher(sources, SingleInternalHelper.toFlowable(), prefetch, ErrorMode.IMMEDIATE)); + return RxJavaPlugins.onAssembly(new FlowableConcatMapSinglePublisher<>(sources, Functions.identity(), ErrorMode.IMMEDIATE, prefetch)); } /** - * Returns a Flowable that emits the items emitted by two Singles, one after the other. + * Returns a {@link Flowable} that emits the items emitted by two {@link SingleSource}s, one after the other. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer.
@@ -284,28 +289,29 @@ public static Flowable concat(@NonNull Publisher the common value type * @param source1 - * a Single to be concatenated + * a {@code SingleSource} to be concatenated * @param source2 - * a Single to be concatenated - * @return a Flowable that emits items emitted by the two source Singles, one after the other. + * a {@code SingleSource} to be concatenated + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @see
ReactiveX operators documentation: Concat */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concat( + public static <@NonNull T> Flowable concat( @NonNull SingleSource source1, @NonNull SingleSource source2 ) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); - return concat(Flowable.fromArray(source1, source2)); + return Flowable.fromArray(source1, source2).concatMapSingleDelayError(Functions.identity(), false); } /** - * Returns a Flowable that emits the items emitted by three Singles, one after the other. + * Returns a {@link Flowable} that emits the items emitted by three {@link SingleSource}s, one after the other. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer.
@@ -315,32 +321,33 @@ public static Flowable concat( * * @param the common value type * @param source1 - * a Single to be concatenated + * a {@code SingleSource} to be concatenated * @param source2 - * a Single to be concatenated + * a {@code SingleSource} to be concatenated * @param source3 - * a Single to be concatenated - * @return a Flowable that emits items emitted by the three source Singles, one after the other. + * a {@code SingleSource} to be concatenated + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} * @see ReactiveX operators documentation: Concat */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concat( + public static <@NonNull T> Flowable concat( @NonNull SingleSource source1, @NonNull SingleSource source2, @NonNull SingleSource source3 ) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); Objects.requireNonNull(source3, "source3 is null"); - return concat(Flowable.fromArray(source1, source2, source3)); + return Flowable.fromArray(source1, source2, source3).concatMapSingleDelayError(Functions.identity(), false); } /** - * Returns a Flowable that emits the items emitted by four Singles, one after the other. + * Returns a {@link Flowable} that emits the items emitted by four {@link SingleSource}s, one after the other. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer.
@@ -350,21 +357,22 @@ public static Flowable concat( * * @param the common value type * @param source1 - * a Single to be concatenated + * a {@code SingleSource} to be concatenated * @param source2 - * a Single to be concatenated + * a {@code SingleSource} to be concatenated * @param source3 - * a Single to be concatenated + * a {@code SingleSource} to be concatenated * @param source4 - * a Single to be concatenated - * @return a Flowable that emits items emitted by the four source Singles, one after the other. + * a {@code SingleSource} to be concatenated + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} * @see ReactiveX operators documentation: Concat */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concat( + public static <@NonNull T> Flowable concat( @NonNull SingleSource source1, @NonNull SingleSource source2, @NonNull SingleSource source3, @NonNull SingleSource source4 ) { @@ -372,43 +380,69 @@ public static Flowable concat( Objects.requireNonNull(source2, "source2 is null"); Objects.requireNonNull(source3, "source3 is null"); Objects.requireNonNull(source4, "source4 is null"); - return concat(Flowable.fromArray(source1, source2, source3, source4)); + return Flowable.fromArray(source1, source2, source3, source4).concatMapSingleDelayError(Functions.identity(), false); } /** - * Concatenate the single values, in a non-overlapping fashion, of the SingleSources provided in + * Concatenate the single values, in a non-overlapping fashion, of the {@link SingleSource}s provided in * an array. *

- * + * *

*
Backpressure:
- *
The returned {@code Flowable} honors the backpressure of the downstream consumer.
+ *
The returned {@link Flowable} honors the backpressure of the downstream consumer.
*
Scheduler:
*
{@code concatArray} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources the array of SingleSource instances - * @return the new Flowable instance + * @param sources the array of {@code SingleSource} instances + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - @SuppressWarnings({ "unchecked", "rawtypes" }) @SafeVarargs - public static Flowable concatArray(@NonNull SingleSource... sources) { - return RxJavaPlugins.onAssembly(new FlowableConcatMap(Flowable.fromArray(sources), SingleInternalHelper.toFlowable(), 2, ErrorMode.BOUNDARY)); + public static <@NonNull T> Flowable concatArray(@NonNull SingleSource... sources) { + return Flowable.fromArray(sources).concatMapSingleDelayError(Functions.identity(), false); } /** - * Concatenates a sequence of SingleSource eagerly into a single stream of values. + * Concatenate the single values, in a non-overlapping fashion, of the {@link SingleSource}s provided in + * an array. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@link Flowable} honors the backpressure of the downstream consumer.
+ *
Scheduler:
+ *
{@code concatArrayDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources the array of {@code SingleSource} instances + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @BackpressureSupport(BackpressureKind.FULL) + @SchedulerSupport(SchedulerSupport.NONE) + @SafeVarargs + public static <@NonNull T> Flowable concatArrayDelayError(@NonNull SingleSource... sources) { + return Flowable.fromArray(sources).concatMapSingleDelayError(Functions.identity(), true); + } + + /** + * Concatenates a sequence of {@link SingleSource} eagerly into a single stream of values. *

* *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source SingleSources. The operator buffers the value emitted by these SingleSources and then drains them - * in order, each one after the previous one completes. + * source {@code SingleSource}s. The operator buffers the value emitted by these {@code SingleSource}s and then drains them + * in order, each one after the previous one succeeds. *

*
Backpressure:
*
The operator honors backpressure from downstream.
@@ -416,54 +450,265 @@ public static Flowable concatArray(@NonNull SingleSource... *
This method does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources a sequence of Single that need to be eagerly concatenated - * @return the new Flowable instance with the specified concatenation behavior + * @param sources a sequence of {@code SingleSource}s that need to be eagerly concatenated + * @return the new {@link Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs - public static Flowable concatArrayEager(@NonNull SingleSource... sources) { + public static <@NonNull T> Flowable concatArrayEager(@NonNull SingleSource... sources) { return Flowable.fromArray(sources).concatMapEager(SingleInternalHelper.toFlowable()); } /** - * Concatenates a Publisher sequence of SingleSources eagerly into a single stream of values. + * Concatenates a sequence of {@link SingleSource} eagerly into a single stream of values. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * source {@code SingleSource}s. The operator buffers the value emitted by these {@code SingleSource}s and then drains them + * in order, each one after the previous one succeeds. + *

+ *
Backpressure:
+ *
The operator honors backpressure from downstream.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code SingleSource}s that need to be eagerly concatenated + * @return the new {@link Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @SafeVarargs + public static <@NonNull T> Flowable concatArrayEagerDelayError(@NonNull SingleSource... sources) { + return Flowable.fromArray(sources).concatMapEagerDelayError(SingleInternalHelper.toFlowable(), true); + } + + /** + * Concatenates the {@link Iterable} sequence of {@link SingleSource}s into a single sequence by subscribing to each {@code SingleSource}, + * one after the other, one at a time and delays any errors till the all inner {@code SingleSource}s terminate + * as a {@link Flowable} sequence. + *

+ * + *

+ *
Backpressure:
+ *
The operator honors backpressure from downstream.
+ *
Scheduler:
+ *
{@code concatDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param the common element base type + * @param sources the {@code Iterable} sequence of {@code SingleSource}s + * @return the new {@code Flowable} with the concatenating behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Flowable concatDelayError(@NonNull Iterable<@NonNull ? extends SingleSource> sources) { + return Flowable.fromIterable(sources).concatMapSingleDelayError(Functions.identity()); + } + + /** + * Concatenates the {@link Publisher} sequence of {@link SingleSource}s into a single sequence by subscribing to each inner {@code SingleSource}, + * one after the other, one at a time and delays any errors till the all inner and the outer {@code Publisher} terminate + * as a {@link Flowable} sequence. + *

+ * + *

+ *
Backpressure:
+ *
{@code concatDelayError} fully supports backpressure.
+ *
Scheduler:
+ *
{@code concatDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param the common element base type + * @param sources the {@code Publisher} sequence of {@code SingleSource}s + * @return the new {@code Flowable} with the concatenating behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Flowable concatDelayError(@NonNull Publisher<@NonNull ? extends SingleSource> sources) { + return Flowable.fromPublisher(sources).concatMapSingleDelayError(Functions.identity()); + } + + /** + * Concatenates the {@link Publisher} sequence of {@link SingleSource}s into a single sequence by subscribing to each inner {@code SingleSource}, + * one after the other, one at a time and delays any errors till the all inner and the outer {@code Publisher} terminate + * as a {@link Flowable} sequence. *

- * + * + *

+ *
Backpressure:
+ *
{@code concatDelayError} fully supports backpressure.
+ *
Scheduler:
+ *
{@code concatDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param the common element base type + * @param sources the {@code Publisher} sequence of {@code SingleSource}s + * @param prefetch The number of upstream items to prefetch so that fresh items are + * ready to be mapped when a previous {@code SingleSource} terminates. + * The operator replenishes after half of the prefetch amount has been consumed + * and turned into {@code SingleSource}s. + * @return the new {@code Flowable} with the concatenating behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive + * @since 3.0.0 + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public static <@NonNull T> Flowable concatDelayError(@NonNull Publisher<@NonNull ? extends SingleSource> sources, int prefetch) { + return Flowable.fromPublisher(sources).concatMapSingleDelayError(Functions.identity(), true, prefetch); + } + + /** + * Concatenates an {@link Iterable} sequence of {@link SingleSource}s eagerly into a single stream of values. + *

+ * *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * emitted source Publishers as they are observed. The operator buffers the values emitted by these - * Publishers and then drains them in order, each one after the previous one completes. + * source {@code SingleSource}s. The operator buffers the values emitted by these {@code SingleSource}s and then drains them + * in order, each one after the previous one succeeds. *

*
Backpressure:
- *
Backpressure is honored towards the downstream and the outer Publisher is + *
Backpressure is honored towards the downstream.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources an {@code Iterable} sequence of {@code SingleSource} that need to be eagerly concatenated + * @return the new {@link Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Flowable concatEager(@NonNull Iterable<@NonNull ? extends SingleSource> sources) { + return Flowable.fromIterable(sources).concatMapEagerDelayError(SingleInternalHelper.toFlowable(), false); + } + + /** + * Concatenates an {@link Iterable} sequence of {@link SingleSource}s eagerly into a single stream of values and + * runs a limited number of the inner sources at once. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * source {@code SingleSource}s. The operator buffers the values emitted by these {@code SingleSource}s and then drains them + * in order, each one after the previous one succeeds. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources an {@code Iterable} sequence of {@code SingleSource} that need to be eagerly concatenated + * @param maxConcurrency the maximum number of concurrently running inner {@code SingleSource}s; {@link Integer#MAX_VALUE} + * is interpreted as all inner {@code SingleSource}s can be active at the same time + * @return the new {@link Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive + * @since 3.0.0 + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Flowable concatEager(@NonNull Iterable<@NonNull ? extends SingleSource> sources, int maxConcurrency) { + return Flowable.fromIterable(sources).concatMapEagerDelayError(SingleInternalHelper.toFlowable(), false, maxConcurrency, 1); + } + + /** + * Concatenates a {@link Publisher} sequence of {@link SingleSource}s eagerly into a single stream of values. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * emitted source {@code SingleSource}s as they are observed. The operator buffers the values emitted by these + * {@code SingleSource}s and then drains them in order, each one after the previous one succeeds. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream and the outer {@code Publisher} is * expected to support backpressure. Violating this assumption, the operator will * signal {@link io.reactivex.rxjava3.exceptions.MissingBackpressureException}.
*
Scheduler:
*
This method does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param sources a sequence of Publishers that need to be eagerly concatenated - * @return the new Publisher instance with the specified concatenation behavior + * @param sources a sequence of {@code SingleSource}s that need to be eagerly concatenated + * @return the new {@link Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concatEager(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable concatEager(@NonNull Publisher<@NonNull ? extends SingleSource> sources) { return Flowable.fromPublisher(sources).concatMapEager(SingleInternalHelper.toFlowable()); } /** - * Concatenates a sequence of SingleSources eagerly into a single stream of values. + * Concatenates a {@link Publisher} sequence of {@link SingleSource}s eagerly into a single stream of values and + * runs a limited number of those inner {@code SingleSource}s at once. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * emitted source {@code SingleSource}s as they are observed. The operator buffers the values emitted by these + * {@code SingleSource}s and then drains them in order, each one after the previous one succeeds. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream and the outer {@code Publisher} is + * expected to support backpressure. Violating this assumption, the operator will + * signal {@link io.reactivex.rxjava3.exceptions.MissingBackpressureException}.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code SingleSource}s that need to be eagerly concatenated + * @param maxConcurrency the maximum number of concurrently running inner {@code SingleSource}s; {@link Integer#MAX_VALUE} + * is interpreted as all inner {@code SingleSource}s can be active at the same time + * @return the new {@link Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive + * @since 3.0.0 + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Flowable concatEager(@NonNull Publisher<@NonNull ? extends SingleSource> sources, int maxConcurrency) { + return Flowable.fromPublisher(sources).concatMapEager(SingleInternalHelper.toFlowable(), maxConcurrency, 1); + } + + /** + * Concatenates an {@link Iterable} sequence of {@link SingleSource}s eagerly into a single stream of values, + * delaying errors until all the inner sources terminate. *

- * + * *

* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source SingleSources. The operator buffers the values emitted by these SingleSources and then drains them - * in order, each one after the previous one completes. + * source {@code SingleSource}s. The operator buffers the values emitted by these {@code SingleSource}s and then drains them + * in order, each one after the previous one succeeds. *

*
Backpressure:
*
Backpressure is honored towards the downstream.
@@ -471,21 +716,120 @@ public static Flowable concatEager(@NonNull PublisherThis method does not operate by default on a particular {@link Scheduler}. *
* @param the value type - * @param sources a sequence of SingleSource that need to be eagerly concatenated - * @return the new Flowable instance with the specified concatenation behavior + * @param sources an {@code Iterable} sequence of {@code SingleSource} that need to be eagerly concatenated + * @return the new {@link Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable concatEager(@NonNull Iterable> sources) { - return Flowable.fromIterable(sources).concatMapEager(SingleInternalHelper.toFlowable()); + public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Iterable<@NonNull ? extends SingleSource> sources) { + return Flowable.fromIterable(sources).concatMapEagerDelayError(SingleInternalHelper.toFlowable(), true); } /** - * Provides an API (via a cold Single) that bridges the reactive world with the callback-style world. + * Concatenates an {@link Iterable} sequence of {@link SingleSource}s eagerly into a single stream of values, + * delaying errors until all the inner sources terminate. + *

+ * *

- * + * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * source {@code SingleSource}s. The operator buffers the values emitted by these {@code SingleSource}s and then drains them + * in order, each one after the previous one succeeds. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources an {@code Iterable} sequence of {@code SingleSource} that need to be eagerly concatenated + * @param maxConcurrency the maximum number of concurrently running inner {@code SingleSource}s; {@link Integer#MAX_VALUE} + * is interpreted as all inner {@code SingleSource}s can be active at the same time + * @return the new {@link Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive + * @since 3.0.0 + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Iterable<@NonNull ? extends SingleSource> sources, int maxConcurrency) { + return Flowable.fromIterable(sources).concatMapEagerDelayError(SingleInternalHelper.toFlowable(), true, maxConcurrency, 1); + } + + /** + * Concatenates a {@link Publisher} sequence of {@link SingleSource}s eagerly into a single stream of values, + * delaying errors until all the inner and the outer sequence terminate. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * emitted source {@code SingleSource}s as they are observed. The operator buffers the values emitted by these + * {@code SingleSource}s and then drains them in order, each one after the previous one succeeds. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream and the outer {@code Publisher} is + * expected to support backpressure. Violating this assumption, the operator will + * signal {@link io.reactivex.rxjava3.exceptions.MissingBackpressureException}.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code SingleSource}s that need to be eagerly concatenated + * @return the new {@link Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Publisher<@NonNull ? extends SingleSource> sources) { + return Flowable.fromPublisher(sources).concatMapEagerDelayError(SingleInternalHelper.toFlowable(), true); + } + + /** + * Concatenates a {@link Publisher} sequence of {@link SingleSource}s eagerly into a single stream of values, + * running at most the specified number of those inner {@code SingleSource}s at once and + * delaying errors until all the inner and the outer sequence terminate. + *

+ * + *

+ * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the + * emitted source {@code SingleSource}s as they are observed. The operator buffers the values emitted by these + * {@code SingleSource}s and then drains them in order, each one after the previous one succeeds. + *

+ *
Backpressure:
+ *
Backpressure is honored towards the downstream and the outer {@code Publisher} is + * expected to support backpressure. Violating this assumption, the operator will + * signal {@link io.reactivex.rxjava3.exceptions.MissingBackpressureException}.
+ *
Scheduler:
+ *
This method does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type + * @param sources a sequence of {@code SingleSource}s that need to be eagerly concatenated + * @param maxConcurrency the number of inner {@code SingleSource}s to run at once + * @return the new {@link Flowable} instance with the specified concatenation behavior + * @throws NullPointerException if {@code sources} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive + * @since 3.0.0 + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Publisher<@NonNull ? extends SingleSource> sources, int maxConcurrency) { + return Flowable.fromPublisher(sources).concatMapEagerDelayError(SingleInternalHelper.toFlowable(), true, maxConcurrency, 1); + } + + /** + * Provides an API (via a cold {@code Single}) that bridges the reactive world with the callback-style world. + *

+ * *

* Example: *


@@ -512,15 +856,16 @@ public static  Flowable concatEager(@NonNull Iterable
      *  
Scheduler:
*
{@code create} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param source the emitter that is called when a SingleObserver subscribes to the returned {@code Single} - * @return the new Single instance + * @param source the emitter that is called when a {@code SingleObserver} subscribes to the returned {@code Single} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source} is {@code null} * @see SingleOnSubscribe * @see Cancellable */ @@ -536,84 +881,88 @@ public static Flowable concatEager(@NonNull Iterable - * + * *
*
Scheduler:
*
{@code defer} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param singleSupplier the {@code Supplier} that is called for each individual {@code SingleObserver} and - * returns a SingleSource instance to subscribe to - * @return the new Single instance + * @param supplier the {@code Supplier} that is called for each individual {@code SingleObserver} and + * returns a {@code SingleSource} instance to subscribe to + * @throws NullPointerException if {@code supplier} is {@code null} + * @return the new {@code Single} instance */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single defer(@NonNull Supplier> singleSupplier) { - Objects.requireNonNull(singleSupplier, "singleSupplier is null"); - return RxJavaPlugins.onAssembly(new SingleDefer<>(singleSupplier)); + public static <@NonNull T> Single defer(@NonNull Supplier> supplier) { + Objects.requireNonNull(supplier, "supplier is null"); + return RxJavaPlugins.onAssembly(new SingleDefer<>(supplier)); } /** - * Signals a Throwable returned by the callback function for each individual SingleObserver. + * Signals a {@link Throwable} returned by the callback function for each individual {@link SingleObserver}. *

- * + * *

*
Scheduler:
*
{@code error} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param errorSupplier the Supplier that is called for each individual SingleObserver and - * returns a Throwable instance to be emitted. - * @return the new Single instance + * @param supplier the {@link Supplier} that is called for each individual {@code SingleObserver} and + * returns a {@code Throwable} instance to be emitted. + * @throws NullPointerException if {@code supplier} is {@code null} + * @return the new {@code Single} instance */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single error(@NonNull Supplier errorSupplier) { - Objects.requireNonNull(errorSupplier, "errorSupplier is null"); - return RxJavaPlugins.onAssembly(new SingleError<>(errorSupplier)); + public static <@NonNull T> Single error(@NonNull Supplier supplier) { + Objects.requireNonNull(supplier, "supplier is null"); + return RxJavaPlugins.onAssembly(new SingleError<>(supplier)); } /** - * Returns a Single that invokes a subscriber's {@link SingleObserver#onError onError} method when the + * Returns a {@code Single} that invokes a subscriber's {@link SingleObserver#onError onError} method when the * subscriber subscribes to it. *

- * + * *

*
Scheduler:
*
{@code error} does not operate by default on a particular {@link Scheduler}.
*
* - * @param exception - * the particular Throwable to pass to {@link SingleObserver#onError onError} + * @param throwable + * the particular {@link Throwable} to pass to {@link SingleObserver#onError onError} * @param - * the type of the item (ostensibly) emitted by the Single - * @return a Single that invokes the subscriber's {@link SingleObserver#onError onError} method when + * the type of the item (ostensibly) emitted by the {@code Single} + * @return the new {@code Single} that invokes the subscriber's {@link SingleObserver#onError onError} method when * the subscriber subscribes to it + * @throws NullPointerException if {@code throwable} is {@code null} * @see ReactiveX operators documentation: Throw */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single error(@NonNull Throwable exception) { - Objects.requireNonNull(exception, "exception is null"); - return error(Functions.justSupplier(exception)); + public static <@NonNull T> Single error(@NonNull Throwable throwable) { + Objects.requireNonNull(throwable, "throwable is null"); + return error(Functions.justSupplier(throwable)); } /** - * Returns a {@link Single} that invokes passed function and emits its result for each new SingleObserver that subscribes. + * Returns a {@code Single} that invokes the given {@link Callable} for each incoming {@link SingleObserver} + * and emits its value or exception to them. *

- * Allows you to defer execution of passed function until SingleObserver subscribes to the {@link Single}. + * Allows you to defer execution of passed function until {@code SingleObserver} subscribes to the {@code Single}. * It makes passed function "lazy". * Result of the function invocation will be emitted by the {@link Single}. *

- * + * *

*
Scheduler:
*
{@code fromCallable} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If the {@link Callable} throws an exception, the respective {@link Throwable} is + *
If the {@code Callable} throws an exception, the respective {@link Throwable} is * delivered to the downstream via {@link SingleObserver#onError(Throwable)}, * except when the downstream has disposed this {@code Single} source. * In this latter case, the {@code Throwable} is delivered to the global error handler via @@ -622,10 +971,11 @@ public static Single error(@NonNull Throwable exception) { *
* * @param callable - * function which execution should be deferred, it will be invoked when SingleObserver will subscribe to the {@link Single}. + * function which execution should be deferred, it will be invoked when {@code SingleObserver} will subscribe to the {@link Single}. * @param - * the type of the item emitted by the {@link Single}. - * @return a {@link Single} whose {@link SingleObserver}s' subscriptions trigger an invocation of the given function. + * the type of the item emitted by the {@code Single}. + * @return the new {@code Single} whose {@code SingleObserver}s' subscriptions trigger an invocation of the given function. + * @throws NullPointerException if {@code callable} is {@code null} * @see #defer(Supplier) * @see #fromSupplier(Supplier) */ @@ -638,27 +988,33 @@ public static Single error(@NonNull Throwable exception) { } /** - * Converts a {@link Future} into a {@code Single}. + * Converts a {@link Future} into a {@code Single} and awaits its outcome in a blocking fashion. *

- * + * *

- * You can convert any object that supports the {@link Future} interface into a Single that emits the return - * value of the {@link Future#get} method of that object, by passing the object into the {@code from} - * method. + * The operator calls {@link Future#get()}, which is a blocking method, on the subscription thread. + * It is recommended applying {@link #subscribeOn(Scheduler)} to move this blocking wait to a + * background thread, and if the {@link Scheduler} supports it, interrupt the wait when the flow + * is disposed. *

- * Important note: This Single is blocking; you cannot dispose it. + * A non-{@code null} value is then emitted via {@code onSuccess} or any exception is emitted via + * {@code onError}. If the {@code Future} completes with {@code null}, a {@link NullPointerException} + * is signaled. *

*
Scheduler:
- *
{@code fromFuture} does not operate by default on a particular {@link Scheduler}.
+ *
{@code fromFuture} does not operate by default on a particular {@code Scheduler}.
*
* * @param future - * the source {@link Future} + * the source {@code Future} * @param - * the type of object that the {@link Future} returns, and also the type of item to be emitted by + * the type of object that the {@code Future} returns, and also the type of item to be emitted by * the resulting {@code Single} - * @return a {@code Single} that emits the item from the source {@link Future} + * @return the new {@code Single} that emits the item from the source {@code Future} + * @throws NullPointerException if {@code future} is {@code null} * @see ReactiveX operators documentation: From + * @see #fromFuture(Future, long, TimeUnit) + * @see #fromCompletionStage(CompletionStage) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -668,30 +1024,34 @@ public static Single error(@NonNull Throwable exception) { } /** - * Converts a {@link Future} into a {@code Single}, with a timeout on the Future. + * Converts a {@link Future} into a {@code Single} and awaits its outcome, or timeout, in a blocking fashion. *

- * + * *

- * You can convert any object that supports the {@link Future} interface into a {@code Single} that emits - * the return value of the {@link Future#get} method of that object, by passing the object into the - * {@code from} method. + * The operator calls {@link Future#get(long, TimeUnit)}, which is a blocking method, on the subscription thread. + * It is recommended applying {@link #subscribeOn(Scheduler)} to move this blocking wait to a + * background thread, and if the {@link Scheduler} supports it, interrupt the wait when the flow + * is disposed. *

- * Important note: This {@code Single} is blocking; you cannot dispose it. + * A non-{@code null} value is then emitted via {@code onSuccess} or any exception is emitted via + * {@code onError}. If the {@code Future} completes with {@code null}, a {@link NullPointerException} + * is signaled. *

*
Scheduler:
- *
{@code fromFuture} does not operate by default on a particular {@link Scheduler}.
+ *
{@code fromFuture} does not operate by default on a particular {@code Scheduler}.
*
* * @param future - * the source {@link Future} + * the source {@code Future} * @param timeout * the maximum time to wait before calling {@code get} * @param unit * the {@link TimeUnit} of the {@code timeout} argument * @param - * the type of object that the {@link Future} returns, and also the type of item to be emitted by + * the type of object that the {@code Future} returns, and also the type of item to be emitted by * the resulting {@code Single} - * @return a {@code Single} that emits the item from the source {@link Future} + * @return the new {@code Single} that emits the item from the source {@code Future} + * @throws NullPointerException if {@code future} or {@code unit} is {@code null} * @see ReactiveX operators documentation: From */ @CheckReturnValue @@ -702,89 +1062,73 @@ public static Single error(@NonNull Throwable exception) { } /** - * Converts a {@link Future} into a {@code Single}, with a timeout on the Future. - *

- * - *

- * You can convert any object that supports the {@link Future} interface into a {@code Single} that emits - * the return value of the {@link Future#get} method of that object, by passing the object into the - * {@code from} method. + * Returns a {@code Single} instance that when subscribed to, subscribes to the {@link MaybeSource} instance and + * emits {@code onSuccess} as a single item, turns an {@code onComplete} into {@link NoSuchElementException} error signal or + * forwards the {@code onError} signal. *

- * Important note: This {@code Single} is blocking; you cannot dispose it. + * *

- *
Scheduler:
- *
You specify the {@link Scheduler} where the blocking wait will happen.
+ *
Scheduler:
+ *
{@code fromMaybe} does not operate by default on a particular {@link Scheduler}.
*
- * - * @param future - * the source {@link Future} - * @param timeout - * the maximum time to wait before calling {@code get} - * @param unit - * the {@link TimeUnit} of the {@code timeout} argument - * @param scheduler - * the Scheduler to use for the blocking wait - * @param - * the type of object that the {@link Future} returns, and also the type of item to be emitted by - * the resulting {@code Single} - * @return a {@code Single} that emits the item from the source {@link Future} - * @see ReactiveX operators documentation: From + * @param the value type of the {@code MaybeSource} element + * @param maybe the {@code MaybeSource} instance to subscribe to, not {@code null} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code maybe} is {@code null} + * @since 3.0.0 */ @CheckReturnValue - @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public static <@NonNull T> Single fromFuture(@NonNull Future future, long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return toSingle(Flowable.fromFuture(future, timeout, unit, scheduler)); + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Single fromMaybe(@NonNull MaybeSource maybe) { + Objects.requireNonNull(maybe, "maybe is null"); + return RxJavaPlugins.onAssembly(new MaybeToSingle<>(maybe, null)); } /** - * Converts a {@link Future}, operating on a specified {@link Scheduler}, into a {@code Single}. - *

- * + * Returns a {@code Single} instance that when subscribed to, subscribes to the {@link MaybeSource} instance and + * emits {@code onSuccess} as a single item, emits the {@code defaultItem} for an {@code onComplete} signal or + * forwards the {@code onError} signal. *

- * You can convert any object that supports the {@link Future} interface into a {@code Single} that emits - * the return value of the {@link Future#get} method of that object, by passing the object into the - * {@code from} method. + * *

- *
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
Scheduler:
+ *
{@code fromMaybe} does not operate by default on a particular {@link Scheduler}.
*
- * - * @param future - * the source {@link Future} - * @param scheduler - * the {@link Scheduler} to wait for the Future on. Use a Scheduler such as - * {@link Schedulers#io()} that can block and wait on the Future - * @param - * the type of object that the {@link Future} returns, and also the type of item to be emitted by - * the resulting {@code Single} - * @return a {@code Single} that emits the item from the source {@link Future} - * @see ReactiveX operators documentation: From + * @param the value type of the {@code MaybeSource} element + * @param maybe the {@code MaybeSource} instance to subscribe to, not {@code null} + * @param defaultItem the item to signal if the current {@code MaybeSource} is empty + * @return the new {@code Single} instance + * @throws NullPointerException if {@code maybe} or {@code defaultItem} is {@code null} + * @since 3.0.0 */ @CheckReturnValue - @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public static <@NonNull T> Single fromFuture(@NonNull Future future, @NonNull Scheduler scheduler) { - return toSingle(Flowable.fromFuture(future, scheduler)); + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Single fromMaybe(@NonNull MaybeSource maybe, @NonNull T defaultItem) { + Objects.requireNonNull(maybe, "maybe is null"); + Objects.requireNonNull(defaultItem, "defaultItem is null"); + return RxJavaPlugins.onAssembly(new MaybeToSingle<>(maybe, defaultItem)); } /** - * Wraps a specific Publisher into a Single and signals its single element or error. - *

If the source Publisher is empty, a NoSuchElementException is signalled. If - * the source has more than one element, an IndexOutOfBoundsException is signalled. + * Wraps a specific {@link Publisher} into a {@code Single} and signals its single element or error. *

- * The {@link Publisher} must follow the - * Reactive-Streams specification. + * + *

+ * If the source {@code Publisher} is empty, a {@link NoSuchElementException} is signaled. If + * the source has more than one element, an {@link IndexOutOfBoundsException} is signaled. + *

+ * The {@code Publisher} must follow the + * Reactive Streams specification. * Violating the specification may result in undefined behavior. *

* If possible, use {@link #create(SingleOnSubscribe)} to create a * source-like {@code Single} instead. *

- * Note that even though {@link Publisher} appears to be a functional interface, it + * Note that even though {@code Publisher} appears to be a functional interface, it * is not recommended to implement it through a lambda as the specification requires * state management that is not achievable with a stateless lambda. - *

- * *

*
Backpressure:
*
The {@code publisher} is consumed in an unbounded fashion but will be cancelled @@ -793,52 +1137,55 @@ public static Single error(@NonNull Throwable exception) { *
{@code fromPublisher} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param publisher the source Publisher instance, not null - * @return the new Single instance + * @param publisher the source {@code Publisher} instance, not {@code null} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code publisher} is {@code null} * @see #create(SingleOnSubscribe) */ @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single fromPublisher(@NonNull Publisher publisher) { + public static <@NonNull T> Single fromPublisher(@NonNull Publisher publisher) { Objects.requireNonNull(publisher, "publisher is null"); return RxJavaPlugins.onAssembly(new SingleFromPublisher<>(publisher)); } /** - * Wraps a specific ObservableSource into a Single and signals its single element or error. - *

If the ObservableSource is empty, a NoSuchElementException is signalled. - * If the source has more than one element, an IndexOutOfBoundsException is signalled. + * Wraps a specific {@link ObservableSource} into a {@code Single} and signals its single element or error. *

- * + * + *

+ * If the {@code ObservableSource} is empty, a {@link NoSuchElementException} is signaled. + * If the source has more than one element, an {@link IndexOutOfBoundsException} is signaled. *

*
Scheduler:
*
{@code fromObservable} does not operate by default on a particular {@link Scheduler}.
*
* - * @param observableSource the source Observable, not null + * @param observable the source sequence to wrap, not {@code null} * @param - * the type of the item emitted by the {@link Single}. - * @return the new Single instance + * the type of the item emitted by the {@code Single}. + * @return the new {@code Single} instance + * @throws NullPointerException if {@code observable} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single fromObservable(@NonNull ObservableSource observableSource) { - Objects.requireNonNull(observableSource, "observableSource is null"); - return RxJavaPlugins.onAssembly(new ObservableSingleSingle<>(observableSource, null)); + public static <@NonNull T> Single fromObservable(@NonNull ObservableSource observable) { + Objects.requireNonNull(observable, "observable is null"); + return RxJavaPlugins.onAssembly(new ObservableSingleSingle<>(observable, null)); } /** - * Returns a {@link Single} that invokes passed supplier and emits its result - * for each new SingleObserver that subscribes. + * Returns a {@code Single} that invokes passed supplier and emits its result + * for each individual {@link SingleObserver} that subscribes. *

- * Allows you to defer execution of passed function until SingleObserver subscribes to the {@link Single}. + * Allows you to defer execution of passed function until a {@code SingleObserver} subscribes to the {@link Single}. * It makes passed function "lazy". * Result of the function invocation will be emitted by the {@link Single}. *

- * + * *

*
Scheduler:
*
{@code fromSupplier} does not operate by default on a particular {@link Scheduler}.
@@ -852,10 +1199,11 @@ public static Single fromObservable(@NonNull ObservableSource * * @param supplier - * function which execution should be deferred, it will be invoked when SingleObserver will subscribe to the {@link Single}. + * function which execution should be deferred, it will be invoked when {@code SingleObserver} subscribes to the {@code Single}. * @param - * the type of the item emitted by the {@link Single}. - * @return a {@link Single} whose {@link SingleObserver}s' subscriptions trigger an invocation of the given function. + * the type of the item emitted by the {@code Single}. + * @return the new {@code Single} whose {@code SingleObserver}s' subscriptions trigger an invocation of the given function. + * @throws NullPointerException if {@code supplier} is {@code null} * @see #defer(Supplier) * @see #fromCallable(Callable) * @since 3.0.0 @@ -871,7 +1219,7 @@ public static Single fromObservable(@NonNull ObservableSource - * + * *

* To convert any object into a {@code Single} that emits that object, pass that object into the * {@code just} method. @@ -884,7 +1232,8 @@ public static Single fromObservable(@NonNull ObservableSource * the type of that item - * @return a {@code Single} that emits {@code item} + * @return the new {@code Single} that emits {@code item} + * @throws NullPointerException if {@code item} is {@code null} * @see ReactiveX operators documentation: Just */ @CheckReturnValue @@ -896,23 +1245,23 @@ public static Single fromObservable(@NonNull ObservableSource - * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer.
*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code SingleSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the source {@code SingleSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Flowable} terminates with that {@code Throwable} and all other source {@code SingleSource}s are disposed. * If more than one {@code SingleSource} signals an error, the resulting {@code Flowable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(Iterable)} to merge sources and terminate only when all source {@code SingleSource}s @@ -920,8 +1269,9 @@ public static Single fromObservable(@NonNull ObservableSource *
* @param the common and resulting value type - * @param sources the Iterable sequence of SingleSource sources - * @return the new Flowable instance + * @param sources the {@code Iterable} sequence of {@code SingleSource} sources + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.0 * @see #mergeDelayError(Iterable) */ @@ -929,28 +1279,28 @@ public static Single fromObservable(@NonNull ObservableSource Flowable merge(@NonNull Iterable> sources) { - return merge(Flowable.fromIterable(sources)); + public static <@NonNull T> Flowable merge(@NonNull Iterable<@NonNull ? extends SingleSource> sources) { + return Flowable.fromIterable(sources).flatMapSingle(Functions.identity()); } /** - * Merges a Flowable sequence of SingleSource instances into a single Flowable sequence, - * running all SingleSources at once. + * Merges a sequence of {@link SingleSource} instances emitted by a {@link Publisher} into a single {@link Flowable} sequence, + * running all {@code SingleSource}s at once. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer.
*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code SingleSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the source {@code SingleSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Flowable} terminates with that {@code Throwable} and all other source {@code SingleSource}s are disposed. * If more than one {@code SingleSource} signals an error, the resulting {@code Flowable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(Publisher)} to merge sources and terminate only when all source {@code SingleSource}s @@ -958,8 +1308,9 @@ public static Flowable merge(@NonNull Iterable *
* @param the common and resulting value type - * @param sources the Flowable sequence of SingleSource sources - * @return the new Flowable instance + * @param sources the {@code Publisher} emitting a sequence of {@code SingleSource}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see #mergeDelayError(Publisher) * @since 2.0 */ @@ -967,22 +1318,21 @@ public static Flowable merge(@NonNull Iterable Flowable merge(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable merge(@NonNull Publisher<@NonNull ? extends SingleSource> sources) { Objects.requireNonNull(sources, "sources is null"); - return RxJavaPlugins.onAssembly(new FlowableFlatMapPublisher(sources, SingleInternalHelper.toFlowable(), false, Integer.MAX_VALUE, Flowable.bufferSize())); + return RxJavaPlugins.onAssembly(new FlowableFlatMapSinglePublisher<>(sources, Functions.identity(), false, Integer.MAX_VALUE)); } /** - * Flattens a {@code Single} that emits a {@code Single} into a single {@code Single} that emits the item - * emitted by the nested {@code Single}, without any transformation. + * Flattens a {@link SingleSource} that emits a {@code SingleSingle} into a single {@code Single} that emits the item + * emitted by the nested {@code SingleSource}, without any transformation. *

- * + * *

*
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
- *
The resulting {@code Single} emits the outer source's or the inner {@code SingleSource}'s {@code Throwable} as is. - * Unlike the other {@code merge()} operators, this operator won't and can't produce a {@code CompositeException} because there is + *
The resulting {@code Single} emits the outer source's or the inner {@code SingleSource}'s {@link Throwable} as is. + * Unlike the other {@code merge()} operators, this operator won't and can't produce a {@link CompositeException} because there is * only one possibility for the outer or the inner {@code SingleSource} to emit an {@code onError} signal. * Therefore, there is no need for a {@code mergeDelayError(SingleSource>)} operator. *
@@ -991,24 +1341,25 @@ public static Flowable merge(@NonNull Publisher the value type of the sources and the output * @param source * a {@code Single} that emits a {@code Single} - * @return a {@code Single} that emits the item that is the result of flattening the {@code Single} emitted + * @return the new {@code Single} that emits the item that is the result of flattening the {@code Single} emitted * by {@code source} + * @throws NullPointerException if {@code source} is {@code null} * @see ReactiveX operators documentation: Merge */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single merge(@NonNull SingleSource> source) { + public static <@NonNull T> Single merge(@NonNull SingleSource> source) { Objects.requireNonNull(source, "source is null"); return RxJavaPlugins.onAssembly(new SingleFlatMap, T>(source, Functions.identity())); } /** - * Flattens two Singles into a single Flowable, without any transformation. + * Flattens two {@link SingleSource}s into one {@link Flowable} sequence, without any transformation. *

- * + * *

- * You can combine items emitted by multiple Singles so that they appear as a single Flowable, by + * You can combine items emitted by multiple {@code SingleSource}s so that they appear as a single {@code Flowable}, by * using the {@code merge} method. *

*
Backpressure:
@@ -1016,13 +1367,13 @@ public static Single merge(@NonNull SingleSourceScheduler: *
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code SingleSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the source {@code SingleSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Flowable} terminates with that {@code Throwable} and all other source {@code SingleSource}s are disposed. * If more than one {@code SingleSource} signals an error, the resulting {@code Flowable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(SingleSource, SingleSource)} to merge sources and terminate only when all source {@code SingleSource}s @@ -1032,10 +1383,11 @@ public static Single merge(@NonNull SingleSource the common value type * @param source1 - * a SingleSource to be merged + * a {@code SingleSource} to be merged * @param source2 - * a SingleSource to be merged - * @return a Flowable that emits all of the items emitted by the source Singles + * a {@code SingleSource} to be merged + * @return the new {@code Flowable} that emits all of the items emitted by the source {@code SingleSource}s + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(SingleSource, SingleSource) */ @@ -1043,20 +1395,20 @@ public static Single merge(@NonNull SingleSource Flowable merge( + public static <@NonNull T> Flowable merge( @NonNull SingleSource source1, @NonNull SingleSource source2 ) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); - return merge(Flowable.fromArray(source1, source2)); + return Flowable.fromArray(source1, source2).flatMapSingle(Functions.identity(), false, Integer.MAX_VALUE); } /** - * Flattens three Singles into a single Flowable, without any transformation. + * Flattens three {@link SingleSource}s into one {@link Flowable} sequence, without any transformation. *

- * + * *

- * You can combine items emitted by multiple Singles so that they appear as a single Flowable, by using + * You can combine items emitted by multiple {@code SingleSource}s so that they appear as a single {@code Flowable}, by * the {@code merge} method. *

*
Backpressure:
@@ -1064,13 +1416,13 @@ public static Flowable merge( *
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code SingleSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the source {@code SingleSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Flowable} terminates with that {@code Throwable} and all other source {@code SingleSource}s are disposed. * If more than one {@code SingleSource} signals an error, the resulting {@code Flowable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(SingleSource, SingleSource, SingleSource)} to merge sources and terminate only when all source {@code SingleSource}s @@ -1080,12 +1432,13 @@ public static Flowable merge( * * @param the common value type * @param source1 - * a SingleSource to be merged + * a {@code SingleSource} to be merged * @param source2 - * a SingleSource to be merged + * a {@code SingleSource} to be merged * @param source3 - * a SingleSource to be merged - * @return a Flowable that emits all of the items emitted by the source Singles + * a {@code SingleSource} to be merged + * @return the new {@code Flowable} that emits all of the items emitted by the source {@code SingleSource}s + * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} * @see ReactiveX operators documentation: Merge * @see #mergeDelayError(SingleSource, SingleSource, SingleSource) */ @@ -1093,22 +1446,22 @@ public static Flowable merge( @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable merge( + public static <@NonNull T> Flowable merge( @NonNull SingleSource source1, @NonNull SingleSource source2, @NonNull SingleSource source3 ) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); Objects.requireNonNull(source3, "source3 is null"); - return merge(Flowable.fromArray(source1, source2, source3)); + return Flowable.fromArray(source1, source2, source3).flatMapSingle(Functions.identity(), false, Integer.MAX_VALUE); } /** - * Flattens four Singles into a single Flowable, without any transformation. + * Flattens four {@link SingleSource}s into one {@link Flowable} sequence, without any transformation. *

- * + * *

- * You can combine items emitted by multiple Singles so that they appear as a single Flowable, by using + * You can combine items emitted by multiple {@code SingleSource}s so that they appear as a single {@code Flowable}, by * the {@code merge} method. *

*
Backpressure:
@@ -1116,13 +1469,13 @@ public static Flowable merge( *
Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
*
Error handling:
- *
If any of the source {@code SingleSource}s signal a {@code Throwable} via {@code onError}, the resulting + *
If any of the source {@code SingleSource}s signal a {@link Throwable} via {@code onError}, the resulting * {@code Flowable} terminates with that {@code Throwable} and all other source {@code SingleSource}s are disposed. * If more than one {@code SingleSource} signals an error, the resulting {@code Flowable} may terminate with the * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@code CompositeException} containing two or more of the various error signals. + * {@link CompositeException} containing two or more of the various error signals. * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@code UndeliverableException} errors. Similarly, {@code Throwable}s + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. * Use {@link #mergeDelayError(SingleSource, SingleSource, SingleSource, SingleSource)} to merge sources and terminate only when all source {@code SingleSource}s @@ -1132,35 +1485,111 @@ public static Flowable merge( * * @param the common value type * @param source1 - * a SingleSource to be merged + * a {@code SingleSource} to be merged * @param source2 - * a SingleSource to be merged + * a {@code SingleSource} to be merged * @param source3 - * a SingleSource to be merged + * a {@code SingleSource} to be merged * @param source4 - * a SingleSource to be merged - * @return a Flowable that emits all of the items emitted by the source Singles + * a {@code SingleSource} to be merged + * @return the new {@code Flowable} that emits all of the items emitted by the source {@code SingleSource}s + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} + * @see ReactiveX operators documentation: Merge + * @see #mergeDelayError(SingleSource, SingleSource, SingleSource, SingleSource) + */ + @CheckReturnValue + @NonNull + @BackpressureSupport(BackpressureKind.FULL) + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Flowable merge( + @NonNull SingleSource source1, @NonNull SingleSource source2, + @NonNull SingleSource source3, @NonNull SingleSource source4 + ) { + Objects.requireNonNull(source1, "source1 is null"); + Objects.requireNonNull(source2, "source2 is null"); + Objects.requireNonNull(source3, "source3 is null"); + Objects.requireNonNull(source4, "source4 is null"); + return Flowable.fromArray(source1, source2, source3, source4).flatMapSingle(Functions.identity(), false, Integer.MAX_VALUE); + } + + /** + * Merges an array of {@link SingleSource} instances into a single {@link Flowable} sequence, + * running all {@code SingleSource}s at once. + *

+ * + *

+ *
Backpressure:
+ *
The operator honors backpressure from downstream.
+ *
Scheduler:
+ *
{@code mergeArray} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If any of the source {@code SingleSource}s signal a {@link Throwable} via {@code onError}, the resulting + * {@code Flowable} terminates with that {@code Throwable} and all other source {@code SingleSource}s are disposed. + * If more than one {@code SingleSource} signals an error, the resulting {@code Flowable} may terminate with the + * first one's error or, depending on the concurrency of the sources, may terminate with a + * {@link CompositeException} containing two or more of the various error signals. + * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s + * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a + * (composite) error will be sent to the same global error handler. + * Use {@link #mergeArrayDelayError(SingleSource...)} to merge sources and terminate only when all source {@code SingleSource}s + * have completed or failed with an error. + *
+ *
+ * @param the common and resulting value type + * @param sources the array sequence of {@code SingleSource} sources + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @see #mergeArrayDelayError(SingleSource...) + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @SafeVarargs + public static <@NonNull T> Flowable mergeArray(SingleSource... sources) { + return Flowable.fromArray(sources).flatMapSingle(Functions.identity(), false, Math.max(1, sources.length)); + } + + /** + * Flattens an array of {@link SingleSource}s into one {@link Flowable}, in a way that allows a subscriber to receive all + * successfully emitted items from each of the source {@code SingleSource}s without being interrupted by an error + * notification from one of them. + *

+ * + *

+ * This behaves like {@link #merge(Publisher)} except that if any of the merged {@code SingleSource}s notify of an + * error via {@link Subscriber#onError onError}, {@code mergeArrayDelayError} will refrain from propagating that + * error notification until all of the merged {@code SingleSource}s have finished emitting items. + *

+ * Even if multiple merged {@code SingleSource}s send {@code onError} notifications, {@code mergeArrayDelayError} will only + * invoke the {@code onError} method of its subscribers once. + *

+ *
Backpressure:
+ *
The operator honors backpressure from downstream.
+ *
Scheduler:
+ *
{@code mergeArrayDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param the common element base type + * @param sources + * the array of {@code SingleSource}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge - * @see #mergeDelayError(SingleSource, SingleSource, SingleSource, SingleSource) */ - @CheckReturnValue - @NonNull @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable merge( - @NonNull SingleSource source1, @NonNull SingleSource source2, - @NonNull SingleSource source3, @NonNull SingleSource source4 - ) { - Objects.requireNonNull(source1, "source1 is null"); - Objects.requireNonNull(source2, "source2 is null"); - Objects.requireNonNull(source3, "source3 is null"); - Objects.requireNonNull(source4, "source4 is null"); - return merge(Flowable.fromArray(source1, source2, source3, source4)); + @SafeVarargs + @NonNull + public static <@NonNull T> Flowable mergeArrayDelayError(@NonNull SingleSource... sources) { + return Flowable.fromArray(sources).flatMapSingle(Functions.identity(), true, Math.max(1, sources.length)); } /** - * Merges an Iterable sequence of SingleSource instances into a single Flowable sequence, - * running all SingleSources at once and delaying any error(s) until all sources succeed or fail. + * Merges an {@link Iterable} sequence of {@link SingleSource} instances into one {@link Flowable} sequence, + * running all {@code SingleSource}s at once and delaying any error(s) until all sources succeed or fail. *

* *

@@ -1171,8 +1600,9 @@ public static Flowable merge( *
*

History: 2.1.9 - experimental * @param the common and resulting value type - * @param sources the Iterable sequence of SingleSource sources - * @return the new Flowable instance + * @param sources the {@code Iterable} sequence of {@code SingleSource}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @see #merge(Iterable) * @since 2.2 */ @@ -1180,13 +1610,13 @@ public static Flowable merge( @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable mergeDelayError(@NonNull Iterable> sources) { - return mergeDelayError(Flowable.fromIterable(sources)); + public static <@NonNull T> Flowable mergeDelayError(@NonNull Iterable<@NonNull ? extends SingleSource> sources) { + return Flowable.fromIterable(sources).flatMapSingle(Functions.identity(), true, Integer.MAX_VALUE); } /** - * Merges a Flowable sequence of SingleSource instances into a single Flowable sequence, - * running all SingleSources at once and delaying any error(s) until all sources succeed or fail. + * Merges a sequence of {@link SingleSource} instances emitted by a {@link Publisher} into a {@link Flowable} sequence, + * running all {@code SingleSource}s at once and delaying any error(s) until all sources succeed or fail. *

* *

@@ -1197,28 +1627,28 @@ public static Flowable mergeDelayError(@NonNull Iterable *

History: 2.1.9 - experimental * @param the common and resulting value type - * @param sources the Flowable sequence of SingleSource sources - * @return the new Flowable instance - * @see #merge(Publisher) + * @param sources the {@code Flowable} sequence of {@code SingleSource}s + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} * @since 2.2 + * @see #merge(Publisher) */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Flowable mergeDelayError(@NonNull Publisher> sources) { + public static <@NonNull T> Flowable mergeDelayError(@NonNull Publisher<@NonNull ? extends SingleSource> sources) { Objects.requireNonNull(sources, "sources is null"); - return RxJavaPlugins.onAssembly(new FlowableFlatMapPublisher(sources, SingleInternalHelper.toFlowable(), true, Integer.MAX_VALUE, Flowable.bufferSize())); + return RxJavaPlugins.onAssembly(new FlowableFlatMapSinglePublisher<>(sources, Functions.identity(), true, Integer.MAX_VALUE)); } /** - * Flattens two Singles into a single Flowable, without any transformation, delaying + * Flattens two {@link SingleSource}s into one {@link Flowable}, without any transformation, delaying * any error(s) until all sources succeed or fail. *

* *

- * You can combine items emitted by multiple Singles so that they appear as a single Flowable, by + * You can combine items emitted by multiple {@code SingleSource}s so that they appear as one {@code Flowable}, by * using the {@code mergeDelayError} method. *

*
Backpressure:
@@ -1229,10 +1659,11 @@ public static Flowable mergeDelayError(@NonNull PublisherHistory: 2.1.9 - experimental * @param the common value type * @param source1 - * a SingleSource to be merged + * a {@code SingleSource} to be merged * @param source2 - * a SingleSource to be merged - * @return a Flowable that emits all of the items emitted by the source Singles + * a {@code SingleSource} to be merged + * @return the new {@code Flowable} that emits all of the items emitted by the source {@code SingleSource}s + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @see ReactiveX operators documentation: Merge * @see #merge(SingleSource, SingleSource) * @since 2.2 @@ -1241,21 +1672,21 @@ public static Flowable mergeDelayError(@NonNull Publisher Flowable mergeDelayError( + public static <@NonNull T> Flowable mergeDelayError( @NonNull SingleSource source1, @NonNull SingleSource source2 ) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); - return mergeDelayError(Flowable.fromArray(source1, source2)); + return Flowable.fromArray(source1, source2).flatMapSingle(Functions.identity(), true, Integer.MAX_VALUE); } /** - * Flattens three Singles into a single Flowable, without any transformation, delaying + * Flattens two {@link SingleSource}s into one {@link Flowable}, without any transformation, delaying * any error(s) until all sources succeed or fail. *

* *

- * You can combine items emitted by multiple Singles so that they appear as a single Flowable, by using + * You can combine items emitted by multiple {@code SingleSource}s so that they appear as one {@code Flowable}, by * the {@code mergeDelayError} method. *

*
Backpressure:
@@ -1266,12 +1697,13 @@ public static Flowable mergeDelayError( *

History: 2.1.9 - experimental * @param the common value type * @param source1 - * a SingleSource to be merged + * a {@code SingleSource} to be merged * @param source2 - * a SingleSource to be merged + * a {@code SingleSource} to be merged * @param source3 - * a SingleSource to be merged - * @return a Flowable that emits all of the items emitted by the source Singles + * a {@code SingleSource} to be merged + * @return the new {@code Flowable} that emits all of the items emitted by the source {@code SingleSource}s + * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} * @see ReactiveX operators documentation: Merge * @see #merge(SingleSource, SingleSource, SingleSource) * @since 2.2 @@ -1280,23 +1712,23 @@ public static Flowable mergeDelayError( @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable mergeDelayError( + public static <@NonNull T> Flowable mergeDelayError( @NonNull SingleSource source1, @NonNull SingleSource source2, @NonNull SingleSource source3 ) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); Objects.requireNonNull(source3, "source3 is null"); - return mergeDelayError(Flowable.fromArray(source1, source2, source3)); + return Flowable.fromArray(source1, source2, source3).flatMapSingle(Functions.identity(), true, Integer.MAX_VALUE); } /** - * Flattens four Singles into a single Flowable, without any transformation, delaying + * Flattens two {@link SingleSource}s into one {@link Flowable}, without any transformation, delaying * any error(s) until all sources succeed or fail. *

* *

- * You can combine items emitted by multiple Singles so that they appear as a single Flowable, by using + * You can combine items emitted by multiple {@code SingleSource}s so that they appear as one {@code Flowable}, by * the {@code mergeDelayError} method. *

*
Backpressure:
@@ -1307,14 +1739,15 @@ public static Flowable mergeDelayError( *

History: 2.1.9 - experimental * @param the common value type * @param source1 - * a SingleSource to be merged + * a {@code SingleSource} to be merged * @param source2 - * a SingleSource to be merged + * a {@code SingleSource} to be merged * @param source3 - * a SingleSource to be merged + * a {@code SingleSource} to be merged * @param source4 - * a SingleSource to be merged - * @return a Flowable that emits all of the items emitted by the source Singles + * a {@code SingleSource} to be merged + * @return the new {@code Flowable} that emits all of the items emitted by the source {@code SingleSource}s + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} * @see ReactiveX operators documentation: Merge * @see #merge(SingleSource, SingleSource, SingleSource, SingleSource) * @since 2.2 @@ -1323,7 +1756,7 @@ public static Flowable mergeDelayError( @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static Flowable mergeDelayError( + public static <@NonNull T> Flowable mergeDelayError( @NonNull SingleSource source1, @NonNull SingleSource source2, @NonNull SingleSource source3, @NonNull SingleSource source4 ) { @@ -1331,13 +1764,13 @@ public static Flowable mergeDelayError( Objects.requireNonNull(source2, "source2 is null"); Objects.requireNonNull(source3, "source3 is null"); Objects.requireNonNull(source4, "source4 is null"); - return mergeDelayError(Flowable.fromArray(source1, source2, source3, source4)); + return Flowable.fromArray(source1, source2, source3, source4).flatMapSingle(Functions.identity(), true, Integer.MAX_VALUE); } /** - * Returns a singleton instance of a never-signaling Single (only calls onSubscribe). + * Returns a singleton instance of a never-signaling {@code Single} (only calls {@code onSubscribe}). *

- * + * *

*
Scheduler:
*
{@code never} does not operate by default on a particular {@link Scheduler}.
@@ -1350,21 +1783,22 @@ public static Flowable mergeDelayError( @SchedulerSupport(SchedulerSupport.NONE) @SuppressWarnings("unchecked") @NonNull - public static Single never() { + public static <@NonNull T> Single never() { return RxJavaPlugins.onAssembly((Single) SingleNever.INSTANCE); } /** - * Signals success with 0L value after the given delay for each SingleObserver. + * Signals success with 0L value after the given delay when a {@link SingleObserver} subscribes. *

- * + * *

*
Scheduler:
*
{@code timer} operates by default on the {@code computation} {@link Scheduler}.
*
* @param delay the delay amount * @param unit the time unit of the delay - * @return the new Single instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code unit} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -1375,20 +1809,21 @@ public static Single timer(long delay, @NonNull TimeUnit unit) { } /** - * Signals success with 0L value after the given delay for each SingleObserver. + * Signals success with 0L value on the specified {@link Scheduler} after the given + * delay when a {@link SingleObserver} subscribes. *

- * + * *

*
Scheduler:
- *
you specify the {@link Scheduler} to signal on.
+ *
you specify the {@code Scheduler} to signal on.
*
* @param delay the delay amount * @param unit the time unit of the delay - * @param scheduler the scheduler where the single 0L will be emitted - * @return the new Single instance + * @param scheduler the {@code Scheduler} where the single 0L will be emitted + * @return the new {@code Single} instance * @throws NullPointerException - * if unit is null, or - * if scheduler is null + * if {@code unit} is {@code null}, or + * if {@code scheduler} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -1401,31 +1836,101 @@ public static Single timer(long delay, @NonNull TimeUnit unit, @NonNull Sc } /** - * Compares two SingleSources and emits true if they emit the same value (compared via Object.equals). + * Compares two {@link SingleSource}s and emits {@code true} if they emit the same value (compared via {@link Object#equals(Object)}). *

- * + * *

*
Scheduler:
- *
{@code equals} does not operate by default on a particular {@link Scheduler}.
+ *
{@code sequenceEqual} does not operate by default on a particular {@link Scheduler}.
*
* @param the common value type - * @param first the first SingleSource instance - * @param second the second SingleSource instance - * @return the new Single instance + * @param source1 the first {@code SingleSource} instance + * @param source2 the second {@code SingleSource} instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single equals(@NonNull SingleSource first, @NonNull SingleSource second) { // NOPMD - Objects.requireNonNull(first, "first is null"); - Objects.requireNonNull(second, "second is null"); - return RxJavaPlugins.onAssembly(new SingleEquals<>(first, second)); + public static <@NonNull T> Single sequenceEqual(@NonNull SingleSource source1, @NonNull SingleSource source2) { // NOPMD + Objects.requireNonNull(source1, "source1 is null"); + Objects.requireNonNull(source2, "source2 is null"); + return RxJavaPlugins.onAssembly(new SingleEquals<>(source1, source2)); + } + + /** + * Switches between {@link SingleSource}s emitted by the source {@link Publisher} whenever + * a new {@code SingleSource} is emitted, disposing the previously running {@code SingleSource}, + * exposing the success items as a {@link Flowable} sequence. + *

+ * + *

+ *
Backpressure:
+ *
The {@code sources} {@code Publisher} is consumed in an unbounded manner (requesting {@link Long#MAX_VALUE}). + * The returned {@code Flowable} respects the backpressure from the downstream.
+ *
Scheduler:
+ *
{@code switchOnNext} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
The returned sequence fails with the first error signaled by the {@code sources} {@code Publisher} + * or the currently running {@code SingleSource}, disposing the rest. Late errors are + * forwarded to the global error handler via {@link RxJavaPlugins#onError(Throwable)}.
+ *
+ * @param the element type of the {@code SingleSource}s + * @param sources the {@code Publisher} sequence of inner {@code SingleSource}s to switch between + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + * @see #switchOnNextDelayError(Publisher) + * @see ReactiveX operators documentation: Switch + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Flowable switchOnNext(@NonNull Publisher<@NonNull ? extends SingleSource> sources) { + Objects.requireNonNull(sources, "sources is null"); + return RxJavaPlugins.onAssembly(new FlowableSwitchMapSinglePublisher<>(sources, Functions.identity(), false)); + } + + /** + * Switches between {@link SingleSource}s emitted by the source {@link Publisher} whenever + * a new {@code SingleSource} is emitted, disposing the previously running {@code SingleSource}, + * exposing the success items as a {@link Flowable} sequence and delaying all errors from + * all of them until all terminate. + *

+ * + *

+ *
Backpressure:
+ *
The {@code sources} {@code Publisher} is consumed in an unbounded manner (requesting {@link Long#MAX_VALUE}). + * The returned {@code Flowable} respects the backpressure from the downstream.
+ *
Scheduler:
+ *
{@code switchOnNextDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
The returned {@code Flowable} collects all errors emitted by either the {@code sources} + * {@code Publisher} or any inner {@code SingleSource} and emits them as a {@link CompositeException} + * when all sources terminate. If only one source ever failed, its error is emitted as-is at the end.
+ *
+ * @param the element type of the {@code SingleSource}s + * @param sources the {@code Publisher} sequence of inner {@code SingleSource}s to switch between + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code sources} is {@code null} + * @since 3.0.0 + * @see #switchOnNext(Publisher) + * @see ReactiveX operators documentation: Switch + */ + @BackpressureSupport(BackpressureKind.FULL) + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public static <@NonNull T> Flowable switchOnNextDelayError(@NonNull Publisher<@NonNull ? extends SingleSource> sources) { + Objects.requireNonNull(sources, "sources is null"); + return RxJavaPlugins.onAssembly(new FlowableSwitchMapSinglePublisher<>(sources, Functions.identity(), true)); } /** - * Advanced use only: creates a Single instance without - * any safeguards by using a callback that is called with a SingleObserver. + * Advanced use only: creates a {@code Single} instance without + * any safeguards by using a callback that is called with a {@link SingleObserver}. *

* *

@@ -1433,8 +1938,9 @@ public static Single equals(@NonNull SingleSource firs *
{@code unsafeCreate} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param onSubscribe the function that is called with the subscribing SingleObserver - * @return the new Single instance + * @param onSubscribe the function that is called with the subscribing {@code SingleObserver} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code onSubscribe} is {@code null} * @throws IllegalArgumentException if {@code source} is a subclass of {@code Single}; such * instances don't need conversion and is possibly a port remnant from 1.x or one should use {@link #hide()} * instead. @@ -1443,7 +1949,7 @@ public static Single equals(@NonNull SingleSource firs @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single unsafeCreate(@NonNull SingleSource onSubscribe) { + public static <@NonNull T> Single unsafeCreate(@NonNull SingleSource onSubscribe) { Objects.requireNonNull(onSubscribe, "onSubscribe is null"); if (onSubscribe instanceof Single) { throw new IllegalArgumentException("unsafeCreate(Single) should be upgraded"); @@ -1452,37 +1958,38 @@ public static Single unsafeCreate(@NonNull SingleSource onSubscribe) { } /** - * Allows using and disposing a resource while running a SingleSource instance generated from + * Allows using and disposing a resource while running a {@link SingleSource} instance generated from * that resource (similar to a try-with-resources). *

- * + * *

*
Scheduler:
*
{@code using} does not operate by default on a particular {@link Scheduler}.
*
- * @param the value type of the SingleSource generated + * @param the value type of the {@code SingleSource} generated * @param the resource type - * @param resourceSupplier the Supplier called for each SingleObserver to generate a resource Object - * @param singleFunction the function called with the returned resource - * Object from {@code resourceSupplier} and should return a SingleSource instance + * @param resourceSupplier the {@link Supplier} called for each {@link SingleObserver} to generate a resource object + * @param sourceSupplier the function called with the returned resource + * object from {@code resourceSupplier} and should return a {@code SingleSource} instance * to be run by the operator - * @param disposer the consumer of the generated resource that is called exactly once for - * that particular resource when the generated SingleSource terminates + * @param resourceCleanup the consumer of the generated resource that is called exactly once for + * that particular resource when the generated {@code SingleSource} terminates * (successfully or with an error) or gets disposed. - * @return the new Single instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code resourceSupplier}, {@code sourceSupplier} and {@code resourceCleanup} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Single using(@NonNull Supplier resourceSupplier, - @NonNull Function> singleFunction, - @NonNull Consumer disposer) { - return using(resourceSupplier, singleFunction, disposer, true); + public static <@NonNull T, @NonNull U> Single using(@NonNull Supplier resourceSupplier, + @NonNull Function> sourceSupplier, + @NonNull Consumer resourceCleanup) { + return using(resourceSupplier, sourceSupplier, resourceCleanup, true); } /** - * Allows using and disposing a resource while running a SingleSource instance generated from + * Allows using and disposing a resource while running a {@link SingleSource} instance generated from * that resource (similar to a try-with-resources). *

* @@ -1490,40 +1997,41 @@ public static Single using(@NonNull Supplier resourceSupplier, *

Scheduler:
*
{@code using} does not operate by default on a particular {@link Scheduler}.
*
- * @param the value type of the SingleSource generated + * @param the value type of the {@code SingleSource} generated * @param the resource type - * @param resourceSupplier the Supplier called for each SingleObserver to generate a resource Object - * @param singleFunction the function called with the returned resource - * Object from {@code resourceSupplier} and should return a SingleSource instance + * @param resourceSupplier the {@link Supplier} called for each {@link SingleObserver} to generate a resource object + * @param sourceSupplier the function called with the returned resource + * object from {@code resourceSupplier} and should return a {@code SingleSource} instance * to be run by the operator - * @param disposer the consumer of the generated resource that is called exactly once for - * that particular resource when the generated SingleSource terminates + * @param resourceCleanup the consumer of the generated resource that is called exactly once for + * that particular resource when the generated {@code SingleSource} terminates * (successfully or with an error) or gets disposed. * @param eager * If {@code true} then resource disposal will happen either on a {@code dispose()} call before the upstream is disposed * or just before the emission of a terminal event ({@code onSuccess} or {@code onError}). * If {@code false} the resource disposal will happen either on a {@code dispose()} call after the upstream is disposed * or just after the emission of a terminal event ({@code onSuccess} or {@code onError}). - * @return the new Single instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code resourceSupplier}, {@code sourceSupplier} or {@code resourceCleanup} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single using( + public static <@NonNull T, @NonNull U> Single using( @NonNull Supplier resourceSupplier, - @NonNull Function> singleFunction, - @NonNull Consumer disposer, + @NonNull Function> sourceSupplier, + @NonNull Consumer resourceCleanup, boolean eager) { Objects.requireNonNull(resourceSupplier, "resourceSupplier is null"); - Objects.requireNonNull(singleFunction, "singleFunction is null"); - Objects.requireNonNull(disposer, "disposer is null"); + Objects.requireNonNull(sourceSupplier, "sourceSupplier is null"); + Objects.requireNonNull(resourceCleanup, "resourceCleanup is null"); - return RxJavaPlugins.onAssembly(new SingleUsing<>(resourceSupplier, singleFunction, disposer, eager)); + return RxJavaPlugins.onAssembly(new SingleUsing<>(resourceSupplier, sourceSupplier, resourceCleanup, eager)); } /** - * Wraps a SingleSource instance into a new Single instance if not already a Single + * Wraps a {@link SingleSource} instance into a new {@code Single} instance if not already a {@code Single} * instance. *

* @@ -1533,12 +2041,13 @@ public static Single using( *

* @param the value type * @param source the source to wrap - * @return the Single wrapper or the source cast to Single (if possible) + * @return the new {@code Single} instance + * @throws NullPointerException if {@code source} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single wrap(@NonNull SingleSource source) { + public static <@NonNull T> Single wrap(@NonNull SingleSource source) { Objects.requireNonNull(source, "source is null"); if (source instanceof Single) { return RxJavaPlugins.onAssembly((Single)source); @@ -1547,20 +2056,20 @@ public static Single wrap(@NonNull SingleSource source) { } /** - * Waits until all SingleSource sources provided by the Iterable sequence signal a success + * Waits until all {@link SingleSource} sources provided by the {@link Iterable} sequence signal a success * value and calls a zipper function with an array of these values to return a result - * to be emitted to downstream. + * to be emitted to the downstream. *

- * If the {@code Iterable} of {@link SingleSource}s is empty a {@link NoSuchElementException} error is signalled after subscription. + * If the {@code Iterable} of {@code SingleSource}s is empty a {@link NoSuchElementException} error is signaled after subscription. *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. * *

* *

- * If any of the SingleSources signal an error, all other SingleSources get disposed and the + * If any of the {@code SingleSources} signal an error, all other {@code SingleSource}s get disposed and the * error emitted to downstream immediately. *

*
Scheduler:
@@ -1568,49 +2077,52 @@ public static Single wrap(@NonNull SingleSource source) { *
* @param the common value type * @param the result value type - * @param sources the Iterable sequence of SingleSource instances. An empty sequence will result in an - * {@code onError} signal of {@link NoSuchElementException}. - * @param zipper the function that receives an array with values from each SingleSource + * @param sources the {@code Iterable} sequence of {@code SingleSource} instances. An empty sequence will result in an + * {@code onError} signal of {@code NoSuchElementException}. + * @param zipper the function that receives an array with values from each {@code SingleSource} * and should return a value to be emitted to downstream - * @return the new Single instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code zipper} or {@code sources} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single zip(@NonNull Iterable> sources, @NonNull Function zipper) { + public static <@NonNull T, @NonNull R> Single zip(@NonNull Iterable<@NonNull ? extends SingleSource> sources, + @NonNull Function zipper) { Objects.requireNonNull(zipper, "zipper is null"); Objects.requireNonNull(sources, "sources is null"); return RxJavaPlugins.onAssembly(new SingleZipIterable<>(sources, zipper)); } /** - * Returns a Single that emits the results of a specified combiner function applied to two items emitted by - * two other Singles. + * Returns a {@code Single} that emits the results of a specified combiner function applied to two items emitted by + * two other {@link SingleSource}s. *

- * + * *

*
Scheduler:
*
{@code zip} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the first source Single's value type - * @param the second source Single's value type + * @param the first source {@code SingleSource}'s value type + * @param the second source {@code SingleSource}'s value type * @param the result value type * @param source1 - * the first source Single + * the first source {@code SingleSource} * @param source2 - * a second source Single + * a second source {@code SingleSource} * @param zipper - * a function that, when applied to the item emitted by each of the source Singles, results in an - * item that will be emitted by the resulting Single - * @return a Single that emits the zipped results + * a function that, when applied to the item emitted by each of the source {@code SingleSource}s, results in an + * item that will be emitted by the resulting {@code Single} + * @return the new {@code Single} that emits the zipped results + * @throws NullPointerException if {@code source1}, {@code source2} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single zip( + public static <@NonNull T1, @NonNull T2, @NonNull R> Single zip( @NonNull SingleSource source1, @NonNull SingleSource source2, @NonNull BiFunction zipper ) { @@ -1621,35 +2133,36 @@ public static Single zip( } /** - * Returns a Single that emits the results of a specified combiner function applied to three items emitted - * by three other Singles. + * Returns a {@code Single} that emits the results of a specified combiner function applied to three items emitted + * by three other {@link SingleSource}s. *

- * + * *

*
Scheduler:
*
{@code zip} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the first source Single's value type - * @param the second source Single's value type - * @param the third source Single's value type + * @param the first source {@code SingleSource}'s value type + * @param the second source {@code SingleSource}'s value type + * @param the third source {@code SingleSource}'s value type * @param the result value type * @param source1 - * the first source Single + * the first source {@code SingleSource} * @param source2 - * a second source Single + * a second source {@code SingleSource} * @param source3 - * a third source Single + * a third source {@code SingleSource} * @param zipper - * a function that, when applied to the item emitted by each of the source Singles, results in an - * item that will be emitted by the resulting Single - * @return a Single that emits the zipped results + * a function that, when applied to the item emitted by each of the source {@code SingleSource}s, results in an + * item that will be emitted by the resulting {@code Single} + * @return the new {@code Single} that emits the zipped results + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull R> Single zip( @NonNull SingleSource source1, @NonNull SingleSource source2, @NonNull SingleSource source3, @NonNull Function3 zipper @@ -1662,38 +2175,39 @@ public static Single zip( } /** - * Returns a Single that emits the results of a specified combiner function applied to four items - * emitted by four other Singles. + * Returns a {@code Single} that emits the results of a specified combiner function applied to four items + * emitted by four other {@link SingleSource}s. *

- * + * *

*
Scheduler:
*
{@code zip} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the first source Single's value type - * @param the second source Single's value type - * @param the third source Single's value type - * @param the fourth source Single's value type + * @param the first source {@code SingleSource}'s value type + * @param the second source {@code SingleSource}'s value type + * @param the third source {@code SingleSource}'s value type + * @param the fourth source {@code SingleSource}'s value type * @param the result value type * @param source1 - * the first source Single + * the first source {@code SingleSource} * @param source2 - * a second source Single + * a second source {@code SingleSource} * @param source3 - * a third source Single + * a third source {@code SingleSource} * @param source4 - * a fourth source Single + * a fourth source {@code SingleSource} * @param zipper - * a function that, when applied to the item emitted by each of the source Singles, results in an - * item that will be emitted by the resulting Single - * @return a Single that emits the zipped results + * a function that, when applied to the item emitted by each of the source {@code SingleSource}s, results in an + * item that will be emitted by the resulting {@code Single} + * @return the new {@code Single} that emits the zipped results + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, {@code source4} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull R> Single zip( @NonNull SingleSource source1, @NonNull SingleSource source2, @NonNull SingleSource source3, @NonNull SingleSource source4, @NonNull Function4 zipper @@ -1707,41 +2221,43 @@ public static Single zip( } /** - * Returns a Single that emits the results of a specified combiner function applied to five items - * emitted by five other Singles. + * Returns a {@code Single} that emits the results of a specified combiner function applied to five items + * emitted by five other {@link SingleSource}s. *

- * + * *

*
Scheduler:
*
{@code zip} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the first source Single's value type - * @param the second source Single's value type - * @param the third source Single's value type - * @param the fourth source Single's value type - * @param the fifth source Single's value type + * @param the first source {@code SingleSource}'s value type + * @param the second source {@code SingleSource}'s value type + * @param the third source {@code SingleSource}'s value type + * @param the fourth source {@code SingleSource}'s value type + * @param the fifth source {@code SingleSource}'s value type * @param the result value type * @param source1 - * the first source Single + * the first source {@code SingleSource} * @param source2 - * a second source Single + * a second source {@code SingleSource} * @param source3 - * a third source Single + * a third source {@code SingleSource} * @param source4 - * a fourth source Single + * a fourth source {@code SingleSource} * @param source5 - * a fifth source Single + * a fifth source {@code SingleSource} * @param zipper - * a function that, when applied to the item emitted by each of the source Singles, results in an - * item that will be emitted by the resulting Single - * @return a Single that emits the zipped results + * a function that, when applied to the item emitted by each of the source {@code SingleSource}s, results in an + * item that will be emitted by the resulting {@code Single} + * @return the new {@code Single} that emits the zipped results + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, {@code source4} + * {@code source5} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull R> Single zip( @NonNull SingleSource source1, @NonNull SingleSource source2, @NonNull SingleSource source3, @NonNull SingleSource source4, @NonNull SingleSource source5, @@ -1757,44 +2273,46 @@ public static Single zip( } /** - * Returns a Single that emits the results of a specified combiner function applied to six items - * emitted by six other Singles. + * Returns a {@code Single} that emits the results of a specified combiner function applied to six items + * emitted by six other {@link SingleSource}s. *

- * + * *

*
Scheduler:
*
{@code zip} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the first source Single's value type - * @param the second source Single's value type - * @param the third source Single's value type - * @param the fourth source Single's value type - * @param the fifth source Single's value type - * @param the sixth source Single's value type + * @param the first source {@code SingleSource}'s value type + * @param the second source {@code SingleSource}'s value type + * @param the third source {@code SingleSource}'s value type + * @param the fourth source {@code SingleSource}'s value type + * @param the fifth source {@code SingleSource}'s value type + * @param the sixth source {@code SingleSource}'s value type * @param the result value type * @param source1 - * the first source Single + * the first source {@code SingleSource} * @param source2 - * a second source Single + * a second source {@code SingleSource} * @param source3 - * a third source Single + * a third source {@code SingleSource} * @param source4 - * a fourth source Single + * a fourth source {@code SingleSource} * @param source5 - * a fifth source Single + * a fifth source {@code SingleSource} * @param source6 - * a sixth source Single + * a sixth source {@code SingleSource} * @param zipper - * a function that, when applied to the item emitted by each of the source Singles, results in an - * item that will be emitted by the resulting Single - * @return a Single that emits the zipped results + * a function that, when applied to the item emitted by each of the source {@code SingleSource}s, results in an + * item that will be emitted by the resulting {@code Single} + * @return the new {@code Single} that emits the zipped results + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, {@code source4} + * {@code source5}, {@code source6} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull R> Single zip( @NonNull SingleSource source1, @NonNull SingleSource source2, @NonNull SingleSource source3, @NonNull SingleSource source4, @NonNull SingleSource source5, @NonNull SingleSource source6, @@ -1811,47 +2329,49 @@ public static Single zip( } /** - * Returns a Single that emits the results of a specified combiner function applied to seven items - * emitted by seven other Singles. + * Returns a {@code Single} that emits the results of a specified combiner function applied to seven items + * emitted by seven other {@link SingleSource}s. *

- * + * *

*
Scheduler:
*
{@code zip} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the first source Single's value type - * @param the second source Single's value type - * @param the third source Single's value type - * @param the fourth source Single's value type - * @param the fifth source Single's value type - * @param the sixth source Single's value type - * @param the seventh source Single's value type + * @param the first source {@code SingleSource}'s value type + * @param the second source {@code SingleSource}'s value type + * @param the third source {@code SingleSource}'s value type + * @param the fourth source {@code SingleSource}'s value type + * @param the fifth source {@code SingleSource}'s value type + * @param the sixth source {@code SingleSource}'s value type + * @param the seventh source {@code SingleSource}'s value type * @param the result value type * @param source1 - * the first source Single + * the first source {@code SingleSource} * @param source2 - * a second source Single + * a second source {@code SingleSource} * @param source3 - * a third source Single + * a third source {@code SingleSource} * @param source4 - * a fourth source Single + * a fourth source {@code SingleSource} * @param source5 - * a fifth source Single + * a fifth source {@code SingleSource} * @param source6 - * a sixth source Single + * a sixth source {@code SingleSource} * @param source7 - * a seventh source Single + * a seventh source {@code SingleSource} * @param zipper - * a function that, when applied to the item emitted by each of the source Singles, results in an - * item that will be emitted by the resulting Single - * @return a Single that emits the zipped results + * a function that, when applied to the item emitted by each of the source {@code SingleSource}s, results in an + * item that will be emitted by the resulting {@code Single} + * @return the new {@code Single} that emits the zipped results + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, {@code source4} + * {@code source5}, {@code source6}, {@code source7} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull R> Single zip( @NonNull SingleSource source1, @NonNull SingleSource source2, @NonNull SingleSource source3, @NonNull SingleSource source4, @NonNull SingleSource source5, @NonNull SingleSource source6, @@ -1870,50 +2390,52 @@ public static Single zip( } /** - * Returns a Single that emits the results of a specified combiner function applied to eight items - * emitted by eight other Singles. + * Returns a {@code Single} that emits the results of a specified combiner function applied to eight items + * emitted by eight other {@link SingleSource}s. *

- * + * *

*
Scheduler:
*
{@code zip} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the first source Single's value type - * @param the second source Single's value type - * @param the third source Single's value type - * @param the fourth source Single's value type - * @param the fifth source Single's value type - * @param the sixth source Single's value type - * @param the seventh source Single's value type - * @param the eighth source Single's value type + * @param the first source {@code SingleSource}'s value type + * @param the second source {@code SingleSource}'s value type + * @param the third source {@code SingleSource}'s value type + * @param the fourth source {@code SingleSource}'s value type + * @param the fifth source {@code SingleSource}'s value type + * @param the sixth source {@code SingleSource}'s value type + * @param the seventh source {@code SingleSource}'s value type + * @param the eighth source {@code SingleSource}'s value type * @param the result value type * @param source1 - * the first source Single + * the first source {@code SingleSource} * @param source2 - * a second source Single + * a second source {@code SingleSource} * @param source3 - * a third source Single + * a third source {@code SingleSource} * @param source4 - * a fourth source Single + * a fourth source {@code SingleSource} * @param source5 - * a fifth source Single + * a fifth source {@code SingleSource} * @param source6 - * a sixth source Single + * a sixth source {@code SingleSource} * @param source7 - * a seventh source Single + * a seventh source {@code SingleSource} * @param source8 - * an eighth source Single + * an eighth source {@code SingleSource} * @param zipper - * a function that, when applied to the item emitted by each of the source Singles, results in an - * item that will be emitted by the resulting Single - * @return a Single that emits the zipped results + * a function that, when applied to the item emitted by each of the source {@code SingleSource}s, results in an + * item that will be emitted by the resulting {@code Single} + * @return the new {@code Single} that emits the zipped results + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, {@code source4} + * {@code source5}, {@code source6}, {@code source7}, {@code source8} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull R> Single zip( @NonNull SingleSource source1, @NonNull SingleSource source2, @NonNull SingleSource source3, @NonNull SingleSource source4, @NonNull SingleSource source5, @NonNull SingleSource source6, @@ -1933,53 +2455,56 @@ public static Single zip( } /** - * Returns a Single that emits the results of a specified combiner function applied to nine items - * emitted by nine other Singles. + * Returns a {@code Single} that emits the results of a specified combiner function applied to nine items + * emitted by nine other {@link SingleSource}s. *

- * + * *

*
Scheduler:
*
{@code zip} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the first source Single's value type - * @param the second source Single's value type - * @param the third source Single's value type - * @param the fourth source Single's value type - * @param the fifth source Single's value type - * @param the sixth source Single's value type - * @param the seventh source Single's value type - * @param the eighth source Single's value type - * @param the ninth source Single's value type + * @param the first source {@code SingleSource}'s value type + * @param the second source {@code SingleSource}'s value type + * @param the third source {@code SingleSource}'s value type + * @param the fourth source {@code SingleSource}'s value type + * @param the fifth source {@code SingleSource}'s value type + * @param the sixth source {@code SingleSource}'s value type + * @param the seventh source {@code SingleSource}'s value type + * @param the eighth source {@code SingleSource}'s value type + * @param the ninth source {@code SingleSource}'s value type * @param the result value type * @param source1 - * the first source Single + * the first source {@code SingleSource} * @param source2 - * a second source Single + * a second source {@code SingleSource} * @param source3 - * a third source Single + * a third source {@code SingleSource} * @param source4 - * a fourth source Single + * a fourth source {@code SingleSource} * @param source5 - * a fifth source Single + * a fifth source {@code SingleSource} * @param source6 - * a sixth source Single + * a sixth source {@code SingleSource} * @param source7 - * a seventh source Single + * a seventh source {@code SingleSource} * @param source8 - * an eighth source Single + * an eighth source {@code SingleSource} * @param source9 - * a ninth source Single + * a ninth source {@code SingleSource} * @param zipper - * a function that, when applied to the item emitted by each of the source Singles, results in an - * item that will be emitted by the resulting Single - * @return a Single that emits the zipped results + * a function that, when applied to the item emitted by each of the source {@code SingleSource}s, results in an + * item that will be emitted by the resulting {@code Single} + * @return the new {@code Single} that emits the zipped results + * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3}, {@code source4} + * {@code source5}, {@code source6}, {@code source7}, {@code source8}, + * {@code source9} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public static Single zip( + public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull T9, @NonNull R> Single zip( @NonNull SingleSource source1, @NonNull SingleSource source2, @NonNull SingleSource source3, @NonNull SingleSource source4, @NonNull SingleSource source5, @NonNull SingleSource source6, @@ -2001,19 +2526,19 @@ public static Single zip( } /** - * Waits until all SingleSource sources provided via an array signal a success + * Waits until all {@link SingleSource} sources provided via an array signal a success * value and calls a zipper function with an array of these values to return a result * to be emitted to downstream. *

* *

- * If the array of {@link SingleSource}s is empty a {@link NoSuchElementException} error is signalled immediately. + * If the array of {@code SingleSource}s is empty a {@link NoSuchElementException} error is signaled immediately. *

* Note on method signature: since Java doesn't allow creating a generic array with {@code new T[]}, the * implementation of this operator has to create an {@code Object[]} instead. Unfortunately, a - * {@code Function} passed to the method would trigger a {@code ClassCastException}. + * {@code Function} passed to the method would trigger a {@link ClassCastException}. *

- * If any of the SingleSources signal an error, all other SingleSources get disposed and the + * If any of the {@code SingleSource}s signal an error, all other {@code SingleSource}s get disposed and the * error emitted to downstream immediately. *

*
Scheduler:
@@ -2021,18 +2546,19 @@ public static Single zip( *
* @param the common value type * @param the result value type - * @param sources the array of SingleSource instances. An empty sequence will result in an - * {@code onError} signal of {@link NoSuchElementException}. - * @param zipper the function that receives an array with values from each SingleSource + * @param sources the array of {@code SingleSource} instances. An empty sequence will result in an + * {@code onError} signal of {@code NoSuchElementException}. + * @param zipper the function that receives an array with values from each {@code SingleSource} * and should return a value to be emitted to downstream - * @return the new Single instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code zipper} or {@code sources} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs - public static Single zipArray(@NonNull Function zipper, @NonNull SingleSource... sources) { + public static <@NonNull T, @NonNull R> Single zipArray(@NonNull Function zipper, @NonNull SingleSource... sources) { Objects.requireNonNull(zipper, "zipper is null"); Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { @@ -2042,16 +2568,17 @@ public static Single zipArray(@NonNull Function - * + * *
*
Scheduler:
*
{@code ambWith} does not operate by default on a particular {@link Scheduler}.
*
- * @param other the other SingleSource to race for the first emission of success or error - * @return the new Single instance. A subscription to this provided source will occur after subscribing + * @param other the other {@code SingleSource} to race for the first emission of success or error + * @return the new {@code Single} instance. A subscription to this provided source will occur after subscribing * to the current source. + * @throws NullPointerException if {@code other} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -2063,15 +2590,15 @@ public final Single ambWith(@NonNull SingleSource other) { } /** - * Hides the identity of the current Single, including the Disposable that is sent + * Hides the identity of the current {@code Single}, including the {@link Disposable} that is sent * to the downstream via {@code onSubscribe()}. *

- * + * *

*
Scheduler:
*
{@code hide} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new Single instance + * @return the new {@code Single} instance * @since 2.0 */ @CheckReturnValue @@ -2082,14 +2609,14 @@ public final Single hide() { } /** - * Transform a Single by applying a particular Transformer function to it. + * Transform a {@code Single} by applying a particular {@link SingleTransformer} function to it. *

- * + * *

- * This method operates on the Single itself whereas {@link #lift} operates on the Single's SingleObservers. + * This method operates on the {@code Single} itself whereas {@link #lift} operates on {@link SingleObserver}s. *

- * If the operator you are creating is designed to act on the individual item emitted by a Single, use - * {@link #lift}. If your operator is designed to transform the source Single as a whole (for instance, by + * If the operator you are creating is designed to act on the individual item emitted by a {@code Single}, use + * {@link #lift}. If your operator is designed to transform the current {@code Single} as a whole (for instance, by * applying a particular set of existing RxJava operators to it) use {@code compose}. *

*
Scheduler:
@@ -2097,30 +2624,31 @@ public final Single hide() { *
* * @param the value type of the single returned by the transformer function - * @param transformer the transformer function, not null - * @return the source Single, transformed by the transformer function + * @param transformer the transformer function, not {@code null} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code transformer} is {@code null} * @see RxJava wiki: Implementing Your Own Operators */ @SuppressWarnings("unchecked") @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single compose(@NonNull SingleTransformer transformer) { + public final <@NonNull R> Single compose(@NonNull SingleTransformer transformer) { return wrap(((SingleTransformer) Objects.requireNonNull(transformer, "transformer is null")).apply(this)); } /** - * Stores the success value or exception from the current Single and replays it to late SingleObservers. + * Stores the success value or exception from the current {@code Single} and replays it to late {@link SingleObserver}s. *

* *

- * The returned Single subscribes to the current Single when the first SingleObserver subscribes. + * The returned {@code Single} subscribes to the current {@code Single} when the first {@code SingleObserver} subscribes. *

*
Scheduler:
*
{@code cache} does not operate by default on a particular {@link Scheduler}.
*
* - * @return the new Single instance + * @return the new {@code Single} instance * @since 2.0 */ @CheckReturnValue @@ -2131,8 +2659,8 @@ public final Single cache() { } /** - * Casts the success value of the current Single into the target type or signals a - * ClassCastException if not compatible. + * Casts the success value of the current {@code Single} into the target type or signals a + * {@link ClassCastException} if not compatible. *

* *

@@ -2140,23 +2668,106 @@ public final Single cache() { *
{@code cast} does not operate by default on a particular {@link Scheduler}.
*
* @param the target type - * @param clazz the type token to use for casting the success result from the current Single - * @return the new Single instance + * @param clazz the type token to use for casting the success result from the current {@code Single} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code clazz} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single cast(@NonNull Class clazz) { + public final <@NonNull U> Single cast(@NonNull Class clazz) { Objects.requireNonNull(clazz, "clazz is null"); return map(Functions.castFunction(clazz)); } /** - * Returns a Flowable that emits the item emitted by the source Single, then the item emitted by the - * specified Single. + * Returns a {@code Single} that is based on applying a specified function to the item emitted by the current {@code Single}, + * where that function returns a {@link SingleSource}. + *

+ * + *

+ * The operator is an alias for {@link #flatMap(Function)} + *

+ *
Scheduler:
+ *
{@code concatMap} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param the result value type + * @param mapper + * a function that, when applied to the item emitted by the current {@code Single}, returns a {@code SingleSource} + * @return the new {@code Single} returned from {@code mapper} when applied to the item emitted by the current {@code Single} + * @throws NullPointerException if {@code mapper} is {@code null} + * @see ReactiveX operators documentation: FlatMap + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final <@NonNull R> Single concatMap(@NonNull Function> mapper) { + Objects.requireNonNull(mapper, "mapper is null"); + return RxJavaPlugins.onAssembly(new SingleFlatMap<>(this, mapper)); + } + + /** + * Returns a {@link Completable} that completes based on applying a specified function to the item emitted by the + * current {@code Single}, where that function returns a {@link CompletableSource}. + *

+ * + *

+ * The operator is an alias for {@link #flatMapCompletable(Function)}. + *

+ *
Scheduler:
+ *
{@code concatMapCompletable} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param mapper + * a function that, when applied to the item emitted by the current {@code Single}, returns a + * {@code CompletableSource} + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @see ReactiveX operators documentation: FlatMap + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final Completable concatMapCompletable(@NonNull Function mapper) { + return flatMapCompletable(mapper); + } + + /** + * Returns a {@link Maybe} that is based on applying a specified function to the item emitted by the current {@code Single}, + * where that function returns a {@link MaybeSource}. + *

+ * + *

+ * The operator is an alias for {@link #flatMapMaybe(Function)}. + *

+ *
Scheduler:
+ *
{@code concatMapMaybe} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param the result value type + * @param mapper + * a function that, when applied to the item emitted by the current {@code Single}, returns a {@code MaybeSource} + * @return the new {@code Maybe} returned from {@code mapper} when applied to the item emitted by the current {@code Single} + * @throws NullPointerException if {@code mapper} is {@code null} + * @see ReactiveX operators documentation: FlatMap + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final <@NonNull R> Maybe concatMapMaybe(@NonNull Function> mapper) { + return flatMapMaybe(mapper); + } + + /** + * Returns a {@link Flowable} that emits the item emitted by the current {@code Single}, then the item emitted by the + * specified {@link SingleSource}. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer.
@@ -2165,9 +2776,10 @@ public final Single cast(@NonNull Class clazz) { *
* * @param other - * a Single to be concatenated after the current - * @return a Flowable that emits the item emitted by the source Single, followed by the item emitted by - * {@code t1} + * a {@code SingleSource} to be concatenated after the current + * @return the new {@code Flowable} that emits the item emitted by the current {@code Single}, followed by the item emitted by + * {@code other} + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: Concat */ @BackpressureSupport(BackpressureKind.FULL) @@ -2179,10 +2791,10 @@ public final Flowable concatWith(@NonNull SingleSource other) { } /** - * Delays the emission of the success signal from the current Single by the specified amount. + * Delays the emission of the success signal from the current {@code Single} by the specified amount. * An error signal will not be delayed. *

- * + * *

*
Scheduler:
*
{@code delay} operates by default on the {@code computation} {@link Scheduler}.
@@ -2190,8 +2802,10 @@ public final Flowable concatWith(@NonNull SingleSource other) { * * @param time the amount of time the success signal should be delayed for * @param unit the time unit - * @return the new Single instance + * @return the new {@code Single} instance * @since 2.0 + * @throws NullPointerException if {@code unit} is {@code null} + * @see #delay(long, TimeUnit, boolean) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @@ -2201,9 +2815,9 @@ public final Single delay(long time, @NonNull TimeUnit unit) { } /** - * Delays the emission of the success or error signal from the current Single by the specified amount. + * Delays the emission of the success or error signal from the current {@code Single} by the specified amount. *

- * + * *

*
Scheduler:
*
{@code delay} operates by default on the {@code computation} {@link Scheduler}.
@@ -2211,8 +2825,9 @@ public final Single delay(long time, @NonNull TimeUnit unit) { *

History: 2.1.5 - experimental * @param time the amount of time the success or error signal should be delayed for * @param unit the time unit - * @param delayError if true, both success and error signals are delayed. if false, only success signals are delayed. - * @return the new Single instance + * @param delayError if {@code true}, both success and error signals are delayed. if {@code false}, only success signals are delayed. + * @return the new {@code Single} instance + * @throws NullPointerException if {@code unit} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -2223,10 +2838,10 @@ public final Single delay(long time, @NonNull TimeUnit unit, boolean delayErr } /** - * Delays the emission of the success signal from the current Single by the specified amount. + * Delays the emission of the success signal from the current {@code Single} by the specified amount. * An error signal will not be delayed. *

- * + * *

*
Scheduler:
*
you specify the {@link Scheduler} where the non-blocking wait and emission happens
@@ -2235,11 +2850,12 @@ public final Single delay(long time, @NonNull TimeUnit unit, boolean delayErr * @param time the amount of time the success signal should be delayed for * @param unit the time unit * @param scheduler the target scheduler to use for the non-blocking wait and emission - * @return the new Single instance + * @return the new {@code Single} instance * @throws NullPointerException - * if unit is null, or - * if scheduler is null + * if {@code unit} is {@code null}, or + * if {@code scheduler} is {@code null} * @since 2.0 + * @see #delay(long, TimeUnit, Scheduler, boolean) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @@ -2249,9 +2865,9 @@ public final Single delay(long time, @NonNull TimeUnit unit, @NonNull Schedul } /** - * Delays the emission of the success or error signal from the current Single by the specified amount. + * Delays the emission of the success or error signal from the current {@code Single} by the specified amount. *

- * + * *

*
Scheduler:
*
you specify the {@link Scheduler} where the non-blocking wait and emission happens
@@ -2260,11 +2876,11 @@ public final Single delay(long time, @NonNull TimeUnit unit, @NonNull Schedul * @param time the amount of time the success or error signal should be delayed for * @param unit the time unit * @param scheduler the target scheduler to use for the non-blocking wait and emission - * @param delayError if true, both success and error signals are delayed. if false, only success signals are delayed. - * @return the new Single instance + * @param delayError if {@code true}, both success and error signals are delayed. if {@code false}, only success signals are delayed. + * @return the new {@code Single} instance * @throws NullPointerException - * if unit is null, or - * if scheduler is null + * if {@code unit} is {@code null}, or + * if {@code scheduler} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -2277,86 +2893,89 @@ public final Single delay(long time, @NonNull TimeUnit unit, @NonNull Schedul } /** - * Delays the actual subscription to the current Single until the given other CompletableSource + * Delays the actual subscription to the current {@code Single} until the given other {@link CompletableSource} * completes. *

* *

If the delaying source signals an error, that error is re-emitted and no subscription - * to the current Single happens. + * to the current {@code Single} happens. *

*
Scheduler:
*
{@code delaySubscription} does not operate by default on a particular {@link Scheduler}.
*
- * @param other the CompletableSource that has to complete before the subscription to the - * current Single happens - * @return the new Single instance + * @param subscriptionIndicator the {@code CompletableSource} that has to complete before the subscription to the + * current {@code Single} happens + * @return the new {@code Single} instance + * @throws NullPointerException if {@code subscriptionIndicator} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single delaySubscription(@NonNull CompletableSource other) { - Objects.requireNonNull(other, "other is null"); - return RxJavaPlugins.onAssembly(new SingleDelayWithCompletable<>(this, other)); + public final Single delaySubscription(@NonNull CompletableSource subscriptionIndicator) { + Objects.requireNonNull(subscriptionIndicator, "subscriptionIndicator is null"); + return RxJavaPlugins.onAssembly(new SingleDelayWithCompletable<>(this, subscriptionIndicator)); } /** - * Delays the actual subscription to the current Single until the given other SingleSource + * Delays the actual subscription to the current {@code Single} until the given other {@link SingleSource} * signals success. *

* *

If the delaying source signals an error, that error is re-emitted and no subscription - * to the current Single happens. + * to the current {@code Single} happens. *

*
Scheduler:
*
{@code delaySubscription} does not operate by default on a particular {@link Scheduler}.
*
* @param the element type of the other source - * @param other the SingleSource that has to complete before the subscription to the - * current Single happens - * @return the new Single instance + * @param subscriptionIndicator the {@code SingleSource} that has to complete before the subscription to the + * current {@code Single} happens + * @return the new {@code Single} instance + * @throws NullPointerException if {@code subscriptionIndicator} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single delaySubscription(@NonNull SingleSource other) { - Objects.requireNonNull(other, "other is null"); - return RxJavaPlugins.onAssembly(new SingleDelayWithSingle<>(this, other)); + public final <@NonNull U> Single delaySubscription(@NonNull SingleSource subscriptionIndicator) { + Objects.requireNonNull(subscriptionIndicator, "subscriptionIndicator is null"); + return RxJavaPlugins.onAssembly(new SingleDelayWithSingle<>(this, subscriptionIndicator)); } /** - * Delays the actual subscription to the current Single until the given other ObservableSource + * Delays the actual subscription to the current {@code Single} until the given other {@link ObservableSource} * signals its first value or completes. *

* *

If the delaying source signals an error, that error is re-emitted and no subscription - * to the current Single happens. + * to the current {@code Single} happens. *

*
Scheduler:
*
{@code delaySubscription} does not operate by default on a particular {@link Scheduler}.
*
* @param the element type of the other source - * @param other the ObservableSource that has to signal a value or complete before the - * subscription to the current Single happens - * @return the new Single instance + * @param subscriptionIndicator the {@code ObservableSource} that has to signal a value or complete before the + * subscription to the current {@code Single} happens + * @return the new {@code Single} instance + * @throws NullPointerException if {@code subscriptionIndicator} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single delaySubscription(@NonNull ObservableSource other) { - Objects.requireNonNull(other, "other is null"); - return RxJavaPlugins.onAssembly(new SingleDelayWithObservable<>(this, other)); + public final <@NonNull U> Single delaySubscription(@NonNull ObservableSource subscriptionIndicator) { + Objects.requireNonNull(subscriptionIndicator, "subscriptionIndicator is null"); + return RxJavaPlugins.onAssembly(new SingleDelayWithObservable<>(this, subscriptionIndicator)); } /** - * Delays the actual subscription to the current Single until the given other Publisher + * Delays the actual subscription to the current {@code Single} until the given other {@link Publisher} * signals its first value or completes. *

* *

If the delaying source signals an error, that error is re-emitted and no subscription - * to the current Single happens. + * to the current {@code Single} happens. *

The other source is consumed in an unbounded manner (requesting {@link Long#MAX_VALUE} from it). *

*
Backpressure:
@@ -2366,32 +2985,34 @@ public final Single delaySubscription(@NonNull ObservableSource other) *
{@code delaySubscription} does not operate by default on a particular {@link Scheduler}.
*
* @param the element type of the other source - * @param other the Publisher that has to signal a value or complete before the - * subscription to the current Single happens - * @return the new Single instance + * @param subscriptionIndicator the {@code Publisher} that has to signal a value or complete before the + * subscription to the current {@code Single} happens + * @return the new {@code Single} instance + * @throws NullPointerException if {@code subscriptionIndicator} is {@code null} * @since 2.0 */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single delaySubscription(@NonNull Publisher other) { - Objects.requireNonNull(other, "other is null"); - return RxJavaPlugins.onAssembly(new SingleDelayWithPublisher<>(this, other)); + public final <@NonNull U> Single delaySubscription(@NonNull Publisher subscriptionIndicator) { + Objects.requireNonNull(subscriptionIndicator, "subscriptionIndicator is null"); + return RxJavaPlugins.onAssembly(new SingleDelayWithPublisher<>(this, subscriptionIndicator)); } /** - * Delays the actual subscription to the current Single until the given time delay elapsed. + * Delays the actual subscription to the current {@code Single} until the given time delay elapsed. *

* *

*
Scheduler:
- *
{@code delaySubscription} does by default subscribe to the current Single + *
{@code delaySubscription} does by default subscribe to the current {@code Single} * on the {@code computation} {@link Scheduler} after the delay.
*
* @param time the time amount to wait with the subscription * @param unit the time unit of the waiting - * @return the new Single instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code unit} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -2402,18 +3023,19 @@ public final Single delaySubscription(long time, @NonNull TimeUnit unit) { } /** - * Delays the actual subscription to the current Single until the given time delay elapsed. + * Delays the actual subscription to the current {@code Single} until the given time delay elapsed. *

* *

*
Scheduler:
- *
{@code delaySubscription} does by default subscribe to the current Single + *
{@code delaySubscription} does by default subscribe to the current {@code Single} * on the {@link Scheduler} you provided, after the delay.
*
* @param time the time amount to wait with the subscription * @param unit the time unit of the waiting - * @param scheduler the scheduler to wait on and subscribe on to the current Single - * @return the new Single instance + * @param scheduler the {@code Scheduler} to wait on and subscribe on to the current {@code Single} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -2424,7 +3046,7 @@ public final Single delaySubscription(long time, @NonNull TimeUnit unit, @Non } /** - * Maps the {@link Notification} success value of this Single back into normal + * Maps the {@link Notification} success value of the current {@code Single} back into normal * {@code onSuccess}, {@code onError} or {@code onComplete} signals as a * {@link Maybe} source. *

@@ -2450,8 +3072,9 @@ public final Single delaySubscription(long time, @NonNull TimeUnit unit, @Non *

History: 2.2.4 - experimental * @param the result type * @param selector the function called with the success item and should - * return a {@link Notification} instance. - * @return the new Maybe instance + * return a {@code Notification} instance. + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code selector} is {@code null} * @since 3.0.0 * @see #materialize() */ @@ -2466,7 +3089,7 @@ public final Single delaySubscription(long time, @NonNull TimeUnit unit, @Non /** * Calls the specified consumer with the success item after this item has been emitted to the downstream. *

- * + * *

* Note that the {@code doAfterSuccess} action is shared between subscriptions and as such * should be thread-safe. @@ -2475,8 +3098,9 @@ public final Single delaySubscription(long time, @NonNull TimeUnit unit, @Non *

{@code doAfterSuccess} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.0.1 - experimental - * @param onAfterSuccess the Consumer that will be called after emitting an item from upstream to the downstream - * @return the new Single instance + * @param onAfterSuccess the {@link Consumer} that will be called after emitting an item from upstream to the downstream + * @return the new {@code Single} instance + * @throws NullPointerException if {@code onAfterSuccess} is {@code null} * @since 2.1 */ @CheckReturnValue @@ -2488,9 +3112,9 @@ public final Single doAfterSuccess(@NonNull Consumer onAfterSucces } /** - * Registers an {@link Action} to be called after this Single invokes either onSuccess or onError. + * Registers an {@link Action} to be called after this {@code Single} invokes either {@code onSuccess} or {@code onError}. *

- * + * *

* Note that the {@code doAfterTerminate} action is shared between subscriptions and as such * should be thread-safe.

@@ -2502,9 +3126,10 @@ public final Single doAfterSuccess(@NonNull Consumer onAfterSucces * *

History: 2.0.6 - experimental * @param onAfterTerminate - * an {@link Action} to be invoked when the source Single finishes - * @return a Single that emits the same items as the source Single, then invokes the - * {@link Action} + * an {@code Action} to be invoked when the current {@code Single} finishes + * @return the new {@code Single} that emits the same items as the current {@code Single}, then invokes the + * {@code Action} + * @throws NullPointerException if {@code onAfterTerminate} is {@code null} * @see ReactiveX operators documentation: Do * @since 2.1 */ @@ -2517,22 +3142,23 @@ public final Single doAfterTerminate(@NonNull Action onAfterTerminate) { } /** - * Calls the specified action after this Single signals onSuccess or onError or gets disposed by + * Calls the specified action after this {@code Single} signals {@code onSuccess} or {@code onError} or gets disposed by * the downstream. *

In case of a race between a terminal event and a dispose call, the provided {@code onFinally} action * is executed once per subscription. *

Note that the {@code onFinally} action is shared between subscriptions and as such * should be thread-safe. *

- * + * *

*
*
Scheduler:
*
{@code doFinally} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.0.1 - experimental - * @param onFinally the action called when this Single terminates or gets disposed - * @return the new Single instance + * @param onFinally the action called when this {@code Single} terminates or gets disposed + * @return the new {@code Single} instance + * @throws NullPointerException if {@code onFinally} is {@code null} * @since 2.1 */ @CheckReturnValue @@ -2544,17 +3170,46 @@ public final Single doFinally(@NonNull Action onFinally) { } /** - * Calls the shared consumer with the Disposable sent through the onSubscribe for each - * SingleObserver that subscribes to the current Single. + * Calls the appropriate {@code onXXX} method (shared between all {@link SingleObserver}s) for the lifecycle events of + * the sequence (subscription, disposal). + *

+ * + *

+ *
Scheduler:
+ *
{@code doOnLifecycle} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param onSubscribe + * a {@link Consumer} called with the {@link Disposable} sent via {@link SingleObserver#onSubscribe(Disposable)} + * @param onDispose + * called when the downstream disposes the {@code Disposable} via {@code dispose()} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code onSubscribe} or {@code onDispose} is {@code null} + * @see ReactiveX operators documentation: Do + * @since 3.0.0 + */ + @CheckReturnValue + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Single doOnLifecycle(@NonNull Consumer onSubscribe, @NonNull Action onDispose) { + Objects.requireNonNull(onSubscribe, "onSubscribe is null"); + Objects.requireNonNull(onDispose, "onDispose is null"); + return RxJavaPlugins.onAssembly(new SingleDoOnLifecycle<>(this, onSubscribe, onDispose)); + } + + /** + * Calls the shared consumer with the {@link Disposable} sent through the {@code onSubscribe} for each + * {@link SingleObserver} that subscribes to the current {@code Single}. *

- * + * *

*
*
Scheduler:
*
{@code doOnSubscribe} does not operate by default on a particular {@link Scheduler}.
*
- * @param onSubscribe the consumer called with the Disposable sent via onSubscribe - * @return the new Single instance + * @param onSubscribe the consumer called with the {@code Disposable} sent via {@code onSubscribe} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code onSubscribe} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -2566,10 +3221,10 @@ public final Single doOnSubscribe(@NonNull Consumer onSub } /** - * Returns a Single instance that calls the given onTerminate callback - * just before this Single completes normally or with an exception. + * Returns a {@code Single} instance that calls the given {@code onTerminate} callback + * just before this {@code Single} completes normally or with an exception. *

- * + * *

* This differs from {@code doAfterTerminate} in that this happens before the {@code onSuccess} or * {@code onError} notification. @@ -2579,7 +3234,8 @@ public final Single doOnSubscribe(@NonNull Consumer onSub *

*

History: 2.2.7 - experimental * @param onTerminate the action to invoke when the consumer calls {@code onSuccess} or {@code onError} - * @return the new Single instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code onTerminate} is {@code null} * @see ReactiveX operators documentation: Do * @see #doOnTerminate(Action) * @since 3.0.0 @@ -2593,17 +3249,18 @@ public final Single doOnTerminate(@NonNull Action onTerminate) { } /** - * Calls the shared consumer with the success value sent via onSuccess for each - * SingleObserver that subscribes to the current Single. + * Calls the shared consumer with the success value sent via {@code onSuccess} for each + * {@link SingleObserver} that subscribes to the current {@code Single}. *

- * + * *

*
*
Scheduler:
*
{@code doOnSuccess} does not operate by default on a particular {@link Scheduler}.
*
- * @param onSuccess the consumer called with the success value of onSuccess - * @return the new Single instance + * @param onSuccess the consumer called with the success value of {@code onSuccess} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code onSuccess} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -2615,8 +3272,8 @@ public final Single doOnSuccess(@NonNull Consumer onSuccess) { } /** - * Calls the shared consumer with the error sent via onError or the value - * via onSuccess for each SingleObserver that subscribes to the current Single. + * Calls the shared consumer with the error sent via {@code onError} or the value + * via {@code onSuccess} for each {@link SingleObserver} that subscribes to the current {@code Single}. *

* *

@@ -2624,29 +3281,31 @@ public final Single doOnSuccess(@NonNull Consumer onSuccess) { *
{@code doOnEvent} does not operate by default on a particular {@link Scheduler}.
*
* @param onEvent the consumer called with the success value of onEvent - * @return the new Single instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code onEvent} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single doOnEvent(@NonNull BiConsumer onEvent) { + public final Single doOnEvent(@NonNull BiConsumer<@Nullable ? super T, @Nullable ? super Throwable> onEvent) { Objects.requireNonNull(onEvent, "onEvent is null"); return RxJavaPlugins.onAssembly(new SingleDoOnEvent<>(this, onEvent)); } /** - * Calls the shared consumer with the error sent via onError for each - * SingleObserver that subscribes to the current Single. + * Calls the shared consumer with the error sent via {@code onError} for each + * {@link SingleObserver} that subscribes to the current {@code Single}. *

- * + * *

*
*
Scheduler:
*
{@code doOnError} does not operate by default on a particular {@link Scheduler}.
*
- * @param onError the consumer called with the success value of onError - * @return the new Single instance + * @param onError the consumer called with the success value of {@code onError} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code onError} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -2658,18 +3317,18 @@ public final Single doOnError(@NonNull Consumer onError) { } /** - * Calls the shared {@code Action} if a SingleObserver subscribed to the current Single - * disposes the common Disposable it received via onSubscribe. + * Calls the shared {@link Action} if a {@link SingleObserver} subscribed to the current {@code Single} + * disposes the common {@link Disposable} it received via {@code onSubscribe}. *

- * + * *

*
*
Scheduler:
*
{@code doOnDispose} does not operate by default on a particular {@link Scheduler}.
*
* @param onDispose the action called when the subscription is disposed - * @return the new Single instance - * @throws NullPointerException if onDispose is null + * @return the new {@code Single} instance + * @throws NullPointerException if {@code onDispose} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -2681,20 +3340,21 @@ public final Single doOnDispose(@NonNull Action onDispose) { } /** - * Filters the success item of the Single via a predicate function and emitting it if the predicate - * returns true, completing otherwise. + * Filters the success item of the {@code Single} via a predicate function and emitting it if the predicate + * returns {@code true}, completing otherwise. *

- * + * *

*
Scheduler:
*
{@code filter} does not operate by default on a particular {@link Scheduler}.
*
* * @param predicate - * a function that evaluates the item emitted by the source Maybe, returning {@code true} + * a function that evaluates the item emitted by the current {@code Single}, returning {@code true} * if it passes the filter - * @return a Maybe that emit the item emitted by the source Maybe that the filter + * @return the new {@link Maybe} that emit the item emitted by the current {@code Single} that the filter * evaluates as {@code true} + * @throws NullPointerException if {@code predicate} is {@code null} * @see ReactiveX operators documentation: Filter */ @CheckReturnValue @@ -2706,10 +3366,10 @@ public final Maybe filter(@NonNull Predicate predicate) { } /** - * Returns a Single that is based on applying a specified function to the item emitted by the source Single, - * where that function returns a SingleSource. + * Returns a {@code Single} that is based on applying a specified function to the item emitted by the current {@code Single}, + * where that function returns a {@link SingleSource}. *

- * + * *

*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
@@ -2717,21 +3377,88 @@ public final Maybe filter(@NonNull Predicate predicate) { * * @param the result value type * @param mapper - * a function that, when applied to the item emitted by the source Single, returns a SingleSource - * @return the Single returned from {@code mapper} when applied to the item emitted by the source Single + * a function that, when applied to the item emitted by the current {@code Single}, returns a {@code SingleSource} + * @return the new {@code Single} returned from {@code mapper} when applied to the item emitted by the current {@code Single} + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single flatMap(@NonNull Function> mapper) { + public final <@NonNull R> Single flatMap(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new SingleFlatMap<>(this, mapper)); } /** - * Returns a Maybe that is based on applying a specified function to the item emitted by the source Single, - * where that function returns a MaybeSource. + * Returns a {@code Single} that emits the results of a specified function to the pair of values emitted by the + * current {@code Single} and a specified mapped {@link SingleSource}. + *

+ * + *

+ *
Scheduler:
+ *
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param + * the type of items emitted by the {@code SingleSource} returned by the {@code mapper} function + * @param + * the type of items emitted by the resulting {@code Single} + * @param mapper + * a function that returns a {@code SingleSource} for the item emitted by the current {@code Single} + * @param combiner + * a function that combines one item emitted by each of the source and collection {@code SingleSource} and + * returns an item to be emitted by the resulting {@code SingleSource} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code mapper} or {@code combiner} is {@code null} + * @see ReactiveX operators documentation: FlatMap + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final <@NonNull U, @NonNull R> Single flatMap(@NonNull Function> mapper, + @NonNull BiFunction combiner) { + Objects.requireNonNull(mapper, "mapper is null"); + Objects.requireNonNull(combiner, "combiner is null"); + return RxJavaPlugins.onAssembly(new SingleFlatMapBiSelector<>(this, mapper, combiner)); + } + + /** + * Maps the {@code onSuccess} or {@code onError} signals of the current {@code Single} into a {@link SingleSource} and emits that + * {@code SingleSource}'s signals. + *

+ * + *

+ *
Scheduler:
+ *
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param + * the result type + * @param onSuccessMapper + * a function that returns a {@code SingleSource} to merge for the {@code onSuccess} item emitted by this {@code Single} + * @param onErrorMapper + * a function that returns a {@code SingleSource} to merge for an {@code onError} notification from this {@code Single} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code onSuccessMapper} or {@code onErrorMapper} is {@code null} + * @see ReactiveX operators documentation: FlatMap + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final <@NonNull R> Single flatMap( + @NonNull Function> onSuccessMapper, + @NonNull Function> onErrorMapper) { + Objects.requireNonNull(onSuccessMapper, "onSuccessMapper is null"); + Objects.requireNonNull(onErrorMapper, "onErrorMapper is null"); + return RxJavaPlugins.onAssembly(new SingleFlatMapNotification<>(this, onSuccessMapper, onErrorMapper)); + } + + /** + * Returns a {@link Maybe} that is based on applying a specified function to the item emitted by the current {@code Single}, + * where that function returns a {@link MaybeSource}. *

* *

@@ -2741,23 +3468,24 @@ public final Single flatMap(@NonNull Function the result value type * @param mapper - * a function that, when applied to the item emitted by the source Single, returns a MaybeSource - * @return the Maybe returned from {@code mapper} when applied to the item emitted by the source Single + * a function that, when applied to the item emitted by the current {@code Single}, returns a {@code MaybeSource} + * @return the new {@code Maybe} returned from {@code mapper} when applied to the item emitted by the current {@code Single} + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Maybe flatMapMaybe(@NonNull Function> mapper) { + public final <@NonNull R> Maybe flatMapMaybe(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new SingleFlatMapMaybe<>(this, mapper)); } /** - * Returns a Flowable that emits items based on applying a specified function to the item emitted by the - * source Single, where that function returns a Publisher. + * Returns a {@link Flowable} that emits items based on applying a specified function to the item emitted by the + * current {@code Single}, where that function returns a {@link Publisher}. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer @@ -2768,22 +3496,23 @@ public final Maybe flatMapMaybe(@NonNull Function the result value type * @param mapper - * a function that, when applied to the item emitted by the source Single, returns a - * Flowable - * @return the Flowable returned from {@code func} when applied to the item emitted by the source Single + * a function that, when applied to the item emitted by the current {@code Single}, returns a + * {@code Publisher} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable flatMapPublisher(@NonNull Function> mapper) { + public final <@NonNull R> Flowable flatMapPublisher(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new SingleFlatMapPublisher<>(this, mapper)); } /** - * Maps the success value of the upstream {@link Single} into an {@link Iterable} and emits its items as a + * Maps the success value of the current {@code Single} into an {@link Iterable} and emits its items as a * {@link Flowable} sequence. *

* @@ -2795,11 +3524,12 @@ public final Flowable flatMapPublisher(@NonNull Function * * @param - * the type of item emitted by the resulting Iterable + * the type of item emitted by the resulting {@code Iterable} * @param mapper - * a function that returns an Iterable sequence of values for when given an item emitted by the - * source Single - * @return the new Flowable instance + * a function that returns an {@code Iterable} sequence of values for when given an item emitted by the + * current {@code Single} + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap * @see #flattenStreamAsFlowable(Function) */ @@ -2807,13 +3537,13 @@ public final Flowable flatMapPublisher(@NonNull Function Flowable flattenAsFlowable(@NonNull Function> mapper) { + public final <@NonNull U> Flowable flattenAsFlowable(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new SingleFlatMapIterableFlowable<>(this, mapper)); } /** - * Maps the success value of the upstream {@link Single} into an {@link Iterable} and emits its items as an + * Maps the success value of the current {@code Single} into an {@link Iterable} and emits its items as an * {@link Observable} sequence. *

* @@ -2823,11 +3553,12 @@ public final Flowable flattenAsFlowable(@NonNull Function * * @param - * the type of item emitted by the resulting Iterable + * the type of item emitted by the resulting {@code Iterable} * @param mapper - * a function that returns an Iterable sequence of values for when given an item emitted by the - * source Single - * @return the new Observable instance + * a function that returns an {@code Iterable} sequence of values for when given an item emitted by the + * current {@code Single} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap * @see #flattenStreamAsObservable(Function) */ @@ -2840,10 +3571,10 @@ public final Flowable flattenAsFlowable(@NonNull Function - * + * *

*
Scheduler:
*
{@code flatMapObservable} does not operate by default on a particular {@link Scheduler}.
@@ -2851,8 +3582,9 @@ public final Flowable flattenAsFlowable(@NonNull Function the result value type * @param mapper - * a function that, when applied to the item emitted by the source Single, returns an ObservableSource - * @return the Observable returned from {@code func} when applied to the item emitted by the source Single + * a function that, when applied to the item emitted by the current {@code Single}, returns an {@code ObservableSource} + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap */ @CheckReturnValue @@ -2865,7 +3597,7 @@ public final Flowable flattenAsFlowable(@NonNull Function * *
@@ -2874,9 +3606,10 @@ public final Flowable flattenAsFlowable(@NonNull Function * * @param mapper - * a function that, when applied to the item emitted by the source Single, returns a - * Completable - * @return the Completable returned from {@code func} when applied to the item emitted by the source Single + * a function that, when applied to the item emitted by the current {@code Single}, returns a + * {@code CompletableSource} + * @return the new {@code Completable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap * @since 2.0 */ @@ -2889,7 +3622,7 @@ public final Completable flatMapCompletable(@NonNull Function * @@ -2912,6 +3645,106 @@ public final T blockingGet() { return observer.blockingGet(); } + /** + * Subscribes to the current {@code Single} and blocks the current thread until it terminates. + *

+ * + *

+ *
Scheduler:
+ *
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If the current {@code Single} signals an error, + * the {@link Throwable} is routed to the global error handler via {@link RxJavaPlugins#onError(Throwable)}. + * If the current thread is interrupted, an {@link InterruptedException} is routed to the same global error handler. + *
+ *
+ * @since 3.0.0 + * @see #blockingSubscribe(Consumer) + * @see #blockingSubscribe(Consumer, Consumer) + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void blockingSubscribe() { + blockingSubscribe(Functions.emptyConsumer(), Functions.ERROR_CONSUMER); + } + + /** + * Subscribes to the current {@code Single} and calls given {@code onSuccess} callback on the current thread + * when it completes normally. + *

+ * + *

+ *
Scheduler:
+ *
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If either the current {@code Single} signals an error or {@code onSuccess} throws, + * the respective {@link Throwable} is routed to the global error handler via {@link RxJavaPlugins#onError(Throwable)}. + * If the current thread is interrupted, an {@link InterruptedException} is routed to the same global error handler. + *
+ *
+ * @param onSuccess the {@link Consumer} to call if the current {@code Single} succeeds + * @throws NullPointerException if {@code onSuccess} is {@code null} + * @since 3.0.0 + * @see #blockingSubscribe(Consumer, Consumer) + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void blockingSubscribe(@NonNull Consumer onSuccess) { + blockingSubscribe(onSuccess, Functions.ERROR_CONSUMER); + } + + /** + * Subscribes to the current {@code Single} and calls the appropriate callback on the current thread + * when it terminates. + *

+ * + *

+ *
Scheduler:
+ *
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
If either {@code onSuccess} or {@code onError} throw, the {@link Throwable} is routed to the + * global error handler via {@link RxJavaPlugins#onError(Throwable)}. + * If the current thread is interrupted, the {@code onError} consumer is called with an {@link InterruptedException}. + *
+ *
+ * @param onSuccess the {@link Consumer} to call if the current {@code Single} succeeds + * @param onError the {@code Consumer} to call if the current {@code Single} signals an error + * @throws NullPointerException if {@code onSuccess} or {@code onError} is {@code null} + * @since 3.0.0 + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void blockingSubscribe(@NonNull Consumer onSuccess, @NonNull Consumer onError) { + Objects.requireNonNull(onSuccess, "onSuccess is null"); + Objects.requireNonNull(onError, "onError is null"); + BlockingMultiObserver observer = new BlockingMultiObserver<>(); + subscribe(observer); + observer.blockingConsume(onSuccess, onError, Functions.EMPTY_ACTION); + } + + /** + * Subscribes to the current {@code Single} and calls the appropriate {@link SingleObserver} method on the current thread. + *

+ * + *

+ *
Scheduler:
+ *
{@code blockingSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
An {@code onError} signal is delivered to the {@link SingleObserver#onError(Throwable)} method. + * If any of the {@code SingleObserver}'s methods throw, the {@link RuntimeException} is propagated to the caller of this method. + * If the current thread is interrupted, an {@link InterruptedException} is delivered to {@code observer.onError}. + *
+ *
+ * @param observer the {@code SingleObserver} to call methods on the current thread + * @throws NullPointerException if {@code observer} is {@code null} + * @since 3.0.0 + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void blockingSubscribe(@NonNull SingleObserver observer) { + Objects.requireNonNull(observer, "observer is null"); + BlockingDisposableMultiObserver blockingObserver = new BlockingDisposableMultiObserver<>(); + observer.onSubscribe(blockingObserver); + subscribe(blockingObserver); + blockingObserver.blockingConsume(observer); + } + /** * This method requires advanced knowledge about building operators, please consider * other standard composition methods first; @@ -3035,39 +3868,40 @@ public final T blockingGet() { * class and creating a {@link SingleTransformer} with it is recommended. *

* Note also that it is not possible to stop the subscription phase in {@code lift()} as the {@code apply()} method - * requires a non-null {@code SingleObserver} instance to be returned, which is then unconditionally subscribed to - * the upstream {@code Single}. For example, if the operator decided there is no reason to subscribe to the + * requires a non-{@code null} {@code SingleObserver} instance to be returned, which is then unconditionally subscribed to + * the current {@code Single}. For example, if the operator decided there is no reason to subscribe to the * upstream source because of some optimization possibility or a failure to prepare the operator, it still has to - * return a {@code SingleObserver} that should immediately dispose the upstream's {@code Disposable} in its + * return a {@code SingleObserver} that should immediately dispose the upstream's {@link Disposable} in its * {@code onSubscribe} method. Again, using a {@code SingleTransformer} and extending the {@code Single} is * a better option as {@link #subscribeActual} can decide to not subscribe to its upstream after all. *

*
Scheduler:
*
{@code lift} does not operate by default on a particular {@link Scheduler}, however, the - * {@link SingleOperator} may use a {@code Scheduler} to support its own asynchronous behavior.
+ * {@code SingleOperator} may use a {@code Scheduler} to support its own asynchronous behavior.
*
* * @param the output value type - * @param lift the {@link SingleOperator} that receives the downstream's {@code SingleObserver} and should return + * @param lift the {@code SingleOperator} that receives the downstream's {@code SingleObserver} and should return * a {@code SingleObserver} with custom behavior to be used as the consumer for the current * {@code Single}. - * @return the new Single instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code lift} is {@code null} * @see RxJava wiki: Writing operators * @see #compose(SingleTransformer) */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single lift(@NonNull SingleOperator lift) { + public final <@NonNull R> Single lift(@NonNull SingleOperator lift) { Objects.requireNonNull(lift, "lift is null"); return RxJavaPlugins.onAssembly(new SingleLift<>(this, lift)); } /** - * Returns a Single that applies a specified function to the item emitted by the source Single and + * Returns a {@code Single} that applies a specified function to the item emitted by the current {@code Single} and * emits the result of this function application. *

- * + * *

*
Scheduler:
*
{@code map} does not operate by default on a particular {@link Scheduler}.
@@ -3075,8 +3909,9 @@ public final Single lift(@NonNull SingleOperator * * @param the result value type * @param mapper - * a function to apply to the item emitted by the Single - * @return a Single that emits the item from the source Single, transformed by the specified function + * a function to apply to the item emitted by the {@code Single} + * @return the new {@code Single} that emits the item from the current {@code Single}, transformed by the specified function + * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: Map */ @CheckReturnValue @@ -3088,16 +3923,16 @@ public final Single lift(@NonNull SingleOperator } /** - * Maps the signal types of this Single into a {@link Notification} of the same kind + * Maps the signal types of this {@code Single} into a {@link Notification} of the same kind * and emits it as a single success value to downstream. *

- * + * *

*
Scheduler:
*
{@code materialize} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.2.4 - experimental - * @return the new Single instance + * @return the new {@code Single} instance * @since 3.0.0 * @see #dematerialize(Function) */ @@ -3109,57 +3944,59 @@ public final Single> materialize() { } /** - * Signals true if the current Single signals a success value that is Object-equals with the value + * Signals {@code true} if the current {@code Single} signals a success value that is {@link Object#equals(Object)} with the value * provided. *

- * + * *

* *

*
Scheduler:
*
{@code contains} does not operate by default on a particular {@link Scheduler}.
*
- * @param value the value to compare against the success value of this Single - * @return the new Single instance + * @param item the value to compare against the success value of this {@code Single} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code item} is {@code null} * @since 2.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single contains(@NonNull Object value) { - return contains(value, ObjectHelper.equalsPredicate()); + public final Single contains(@NonNull Object item) { + return contains(item, ObjectHelper.equalsPredicate()); } /** - * Signals true if the current Single signals a success value that is equal with - * the value provided by calling a bi-predicate. + * Signals {@code true} if the current {@code Single} signals a success value that is equal with + * the value provided by calling a {@link BiPredicate}. *

* *

*
Scheduler:
*
{@code contains} does not operate by default on a particular {@link Scheduler}.
*
- * @param value the value to compare against the success value of this Single - * @param comparer the function that receives the success value of this Single, the value provided - * and should return true if they are considered equal - * @return the new Single instance + * @param item the value to compare against the success value of this {@code Single} + * @param comparer the function that receives the success value of this {@code Single}, the value provided + * and should return {@code true} if they are considered equal + * @return the new {@code Single} instance + * @throws NullPointerException if {@code item} or {@code comparer} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single contains(@NonNull Object value, @NonNull BiPredicate comparer) { - Objects.requireNonNull(value, "value is null"); + public final Single contains(@NonNull Object item, @NonNull BiPredicate comparer) { + Objects.requireNonNull(item, "item is null"); Objects.requireNonNull(comparer, "comparer is null"); - return RxJavaPlugins.onAssembly(new SingleContains<>(this, value, comparer)); + return RxJavaPlugins.onAssembly(new SingleContains<>(this, item, comparer)); } /** - * Flattens this and another Single into a single Flowable, without any transformation. + * Flattens this {@code Single} and another {@link SingleSource} into one {@link Flowable}, without any transformation. *

- * + * *

- * You can combine items emitted by multiple Singles so that they appear as a single Flowable, by using + * You can combine items emitted by multiple {@code SingleSource}s so that they appear as one {@code Flowable}, by using * the {@code mergeWith} method. *

*
Backpressure:
@@ -3169,8 +4006,9 @@ public final Single contains(@NonNull Object value, @NonNull BiPredicat *
* * @param other - * a SingleSource to be merged - * @return that emits all of the items emitted by the source Singles + * a {@code SingleSource} to be merged + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: Merge */ @BackpressureSupport(BackpressureKind.FULL) @@ -3180,22 +4018,46 @@ public final Single contains(@NonNull Object value, @NonNull BiPredicat public final Flowable mergeWith(@NonNull SingleSource other) { return merge(this, other); } + /** + * Filters the items emitted by the current {@code Single}, only emitting its success value if that + * is an instance of the supplied {@link Class}. + *

+ * + *

+ *
Scheduler:
+ *
{@code ofType} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param the output type + * @param clazz + * the class type to filter the items emitted by the current {@code Single} + * @return the new {@link Maybe} instance + * @throws NullPointerException if {@code clazz} is {@code null} + * @see ReactiveX operators documentation: Filter + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final <@NonNull U> Maybe ofType(@NonNull Class clazz) { + Objects.requireNonNull(clazz, "clazz is null"); + return filter(Functions.isInstanceOf(clazz)).cast(clazz); + } /** - * Modifies a Single to emit its item (or notify of its error) on a specified {@link Scheduler}, + * Signals the success item or the terminal signals of the current {@code Single} on the specified {@link Scheduler}, * asynchronously. *

- * + * *

*
Scheduler:
- *
you specify which {@link Scheduler} this operator will use.
+ *
you specify which {@code Scheduler} this operator will use.
*
* * @param scheduler - * the {@link Scheduler} to notify subscribers on - * @return the source Single modified so that its subscribers are notified on the specified - * {@link Scheduler} - * @throws NullPointerException if scheduler is null + * the {@code Scheduler} to notify subscribers on + * @return the new {@code Single} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: ObserveOn * @see RxJava Threading Examples * @see #subscribeOn @@ -3209,108 +4071,154 @@ public final Single observeOn(@NonNull Scheduler scheduler) { } /** - * Instructs a Single to emit an item (returned by a specified function) rather than invoking - * {@link SingleObserver#onError onError} if it encounters an error. + * Ends the flow with a success item returned by a function for the {@link Throwable} error signaled by the current + * {@code Single} instead of signaling the error via {@code onError}. + *

+ * + *

+ * By default, when a {@code Single} encounters an error that prevents it from emitting the expected item to its + * subscriber, the {@code Single} invokes its subscriber's {@link SingleObserver#onError} method, and then quits + * without invoking any more of its observer's methods. The {@code onErrorReturn} method changes this + * behavior. If you pass a function ({@code resumeFunction}) to a {@code Single}'s {@code onErrorReturn} method, if + * the original {@code Single} encounters an error, instead of invoking its observer's + * {@link SingleObserver#onError} method, it will instead emit the return value of {@code resumeFunction}. + *

+ * You can use this to prevent errors from propagating or to supply fallback data should errors be + * encountered. + *

+ *
Scheduler:
+ *
{@code onErrorReturn} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param itemSupplier + * a function that returns an item that the new {@code Single} will emit if the current {@code Single} encounters + * an error + * @return the new {@code Single} instance + * @throws NullPointerException if {@code itemSupplier} is {@code null} + * @see ReactiveX operators documentation: Catch + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final Single onErrorReturn(@NonNull Function itemSupplier) { + Objects.requireNonNull(itemSupplier, "itemSupplier is null"); + return RxJavaPlugins.onAssembly(new SingleOnErrorReturn<>(this, itemSupplier, null)); + } + + /** + * Signals the specified value as success in case the current {@code Single} signals an error. + *

+ * + *

+ *
Scheduler:
+ *
{@code onErrorReturnItem} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param item the value to signal if the current {@code Single} fails + * @return the new {@code Single} instance + * @throws NullPointerException if {@code item} is {@code null} + * @since 2.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final Single onErrorReturnItem(@NonNull T item) { + Objects.requireNonNull(item, "item is null"); + return RxJavaPlugins.onAssembly(new SingleOnErrorReturn<>(this, null, item)); + } + + /** + * Resumes the flow with the given {@link SingleSource} when the current {@code Single} fails instead of + * signaling the error via {@code onError}. *

- * + * *

- * By default, when a Single encounters an error that prevents it from emitting the expected item to its - * subscriber, the Single invokes its subscriber's {@link SingleObserver#onError} method, and then quits - * without invoking any more of its subscriber's methods. The {@code onErrorReturn} method changes this - * behavior. If you pass a function ({@code resumeFunction}) to a Single's {@code onErrorReturn} method, if - * the original Single encounters an error, instead of invoking its subscriber's - * {@link SingleObserver#onError} method, it will instead emit the return value of {@code resumeFunction}. + * By default, when a {@code Single} encounters an error that prevents it from emitting the expected item to + * its {@link SingleObserver}, the {@code Single} invokes its {@code SingleObserver}'s {@code onError} method, and then quits + * without invoking any more of its {@code SingleObserver}'s methods. The {@code onErrorResumeWith} method changes this + * behavior. If you pass another {@code Single} ({@code resumeSingleInCaseOfError}) to a {@code Single}'s + * {@code onErrorResumeWith} method, if the original {@code Single} encounters an error, instead of invoking its + * {@code SingleObserver}'s {@code onError} method, it will instead relinquish control to {@code resumeSingleInCaseOfError} which + * will invoke the {@code SingleObserver}'s {@link SingleObserver#onSuccess onSuccess} method if it is able to do so. In such a case, + * because no {@code Single} necessarily invokes {@code onError}, the {@code SingleObserver} may never know that an error + * happened. *

* You can use this to prevent errors from propagating or to supply fallback data should errors be * encountered. *

*
Scheduler:
- *
{@code onErrorReturn} does not operate by default on a particular {@link Scheduler}.
+ *
{@code onErrorResumeWith} does not operate by default on a particular {@link Scheduler}.
*
* - * @param resumeFunction - * a function that returns an item that the new Single will emit if the source Single encounters - * an error - * @return the original Single with appropriately modified behavior + * @param fallback a {@code Single} that will take control if source {@code Single} encounters an error. + * @return the new {@code Single} instance + * @throws NullPointerException if {@code fallback} is {@code null} * @see ReactiveX operators documentation: Catch */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single onErrorReturn(@NonNull Function resumeFunction) { - Objects.requireNonNull(resumeFunction, "resumeFunction is null"); - return RxJavaPlugins.onAssembly(new SingleOnErrorReturn<>(this, resumeFunction, null)); + public final Single onErrorResumeWith(@NonNull SingleSource fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return onErrorResumeNext(Functions.justFunction(fallback)); } /** - * Signals the specified value as success in case the current Single signals an error. + * Returns a {@link Maybe} instance that if the current {@code Single} emits an error, it will emit an {@code onComplete} + * and swallow the throwable. *

- * + * *

- *
Scheduler:
- *
{@code onErrorReturnItem} does not operate by default on a particular {@link Scheduler}.
+ *
Scheduler:
+ *
{@code onErrorComplete} does not operate by default on a particular {@link Scheduler}.
*
- * @param value the value to signal if the current Single fails - * @return the new Single instance - * @since 2.0 + * @return the new {@code Maybe} instance + * @since 3.0.0 */ @CheckReturnValue - @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single onErrorReturnItem(@NonNull T value) { - Objects.requireNonNull(value, "value is null"); - return RxJavaPlugins.onAssembly(new SingleOnErrorReturn<>(this, null, value)); + @NonNull + public final Maybe onErrorComplete() { + return onErrorComplete(Functions.alwaysTrue()); } /** - * Instructs a Single to pass control to another Single rather than invoking - * {@link SingleObserver#onError(Throwable)} if it encounters an error. - *

- * - *

- * By default, when a Single encounters an error that prevents it from emitting the expected item to - * its {@link SingleObserver}, the Single invokes its SingleObserver's {@code onError} method, and then quits - * without invoking any more of its SingleObserver's methods. The {@code onErrorResumeWith} method changes this - * behavior. If you pass another Single ({@code resumeSingleInCaseOfError}) to a Single's - * {@code onErrorResumeWith} method, if the original Single encounters an error, instead of invoking its - * SingleObserver's {@code onError} method, it will instead relinquish control to {@code resumeSingleInCaseOfError} which - * will invoke the SingleObserver's {@link SingleObserver#onSuccess onSuccess} method if it is able to do so. In such a case, - * because no Single necessarily invokes {@code onError}, the SingleObserver may never know that an error - * happened. + * Returns a {@link Maybe} instance that if this {@code Single} emits an error and the predicate returns + * {@code true}, it will emit an {@code onComplete} and swallow the throwable. *

- * You can use this to prevent errors from propagating or to supply fallback data should errors be - * encountered. + * *

- *
Scheduler:
- *
{@code onErrorResumeWith} does not operate by default on a particular {@link Scheduler}.
+ *
Scheduler:
+ *
{@code onErrorComplete} does not operate by default on a particular {@link Scheduler}.
*
- * - * @param resumeSingleInCaseOfError a Single that will take control if source Single encounters an error. - * @return the original Single, with appropriately modified behavior. - * @see ReactiveX operators documentation: Catch + * @param predicate the predicate to call when an {@link Throwable} is emitted which should return {@code true} + * if the {@code Throwable} should be swallowed and replaced with an {@code onComplete}. + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code predicate} is {@code null} + * @since 3.0.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single onErrorResumeWith(@NonNull SingleSource resumeSingleInCaseOfError) { - Objects.requireNonNull(resumeSingleInCaseOfError, "resumeSingleInCaseOfError is null"); - return onErrorResumeNext(Functions.justFunction(resumeSingleInCaseOfError)); + public final Maybe onErrorComplete(@NonNull Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + + return RxJavaPlugins.onAssembly(new SingleOnErrorComplete<>(this, predicate)); } /** - * Instructs a Single to pass control to another Single rather than invoking - * {@link SingleObserver#onError(Throwable)} if it encounters an error. + * Resumes the flow with a {@link SingleSource} returned for the failure {@link Throwable} of the current {@code Single} by a + * function instead of signaling the error via {@code onError}. *

- * + * *

- * By default, when a Single encounters an error that prevents it from emitting the expected item to - * its {@link SingleObserver}, the Single invokes its SingleObserver's {@code onError} method, and then quits - * without invoking any more of its SingleObserver's methods. The {@code onErrorResumeNext} method changes this - * behavior. If you pass a function that will return another Single ({@code resumeFunctionInCaseOfError}) to a Single's - * {@code onErrorResumeNext} method, if the original Single encounters an error, instead of invoking its - * SingleObserver's {@code onError} method, it will instead relinquish control to {@code resumeSingleInCaseOfError} which - * will invoke the SingleObserver's {@link SingleObserver#onSuccess onSuccess} method if it is able to do so. In such a case, - * because no Single necessarily invokes {@code onError}, the SingleObserver may never know that an error + * By default, when a {@code Single} encounters an error that prevents it from emitting the expected item to + * its {@link SingleObserver}, the {@code Single} invokes its {@code SingleObserver}'s {@code onError} method, and then quits + * without invoking any more of its {@code SingleObserver}'s methods. The {@code onErrorResumeNext} method changes this + * behavior. If you pass a function that will return another {@code Single} ({@code resumeFunctionInCaseOfError}) to a {@code Single}'s + * {@code onErrorResumeNext} method, if the original {@code Single} encounters an error, instead of invoking its + * {@code SingleObserver}'s {@code onError} method, it will instead relinquish control to {@code resumeSingleInCaseOfError} which + * will invoke the {@code SingleObserver}'s {@link SingleObserver#onSuccess onSuccess} method if it is able to do so. In such a case, + * because no {@code Single} necessarily invokes {@code onError}, the {@code SingleObserver} may never know that an error * happened. *

* You can use this to prevent errors from propagating or to supply fallback data should errors be @@ -3320,8 +4228,9 @@ public final Single onErrorResumeWith(@NonNull SingleSource resu *

{@code onErrorResumeNext} does not operate by default on a particular {@link Scheduler}.
*
* - * @param resumeFunctionInCaseOfError a function that returns a Single that will take control if source Single encounters an error. - * @return the original Single, with appropriately modified behavior. + * @param fallbackSupplier a function that returns a {@code SingleSource} that will take control if source {@code Single} encounters an error. + * @return the new {@code Single} instance + * @throws NullPointerException if {@code fallbackSupplier} is {@code null} * @see ReactiveX operators documentation: Catch * @since .20 */ @@ -3329,14 +4238,14 @@ public final Single onErrorResumeWith(@NonNull SingleSource resu @NonNull @SchedulerSupport(SchedulerSupport.NONE) public final Single onErrorResumeNext( - @NonNull Function> resumeFunctionInCaseOfError) { - Objects.requireNonNull(resumeFunctionInCaseOfError, "resumeFunctionInCaseOfError is null"); - return RxJavaPlugins.onAssembly(new SingleResumeNext<>(this, resumeFunctionInCaseOfError)); + @NonNull Function> fallbackSupplier) { + Objects.requireNonNull(fallbackSupplier, "fallbackSupplier is null"); + return RxJavaPlugins.onAssembly(new SingleResumeNext<>(this, fallbackSupplier)); } /** - * Nulls out references to the upstream producer and downstream SingleObserver if - * the sequence is terminated or downstream calls dispose(). + * Nulls out references to the upstream producer and downstream {@link SingleObserver} if + * the sequence is terminated or downstream calls {@code dispose()}. *

* *

@@ -3344,8 +4253,8 @@ public final Single onErrorResumeNext( *
{@code onTerminateDetach} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.1.5 - experimental - * @return a Single which nulls out references to the upstream producer and downstream SingleObserver if - * the sequence is terminated or downstream calls dispose() + * @return the new {@code Single} which {@code null}s out references to the upstream producer and downstream {@code SingleObserver} if + * the sequence is terminated or downstream calls {@code dispose()} * @since 2.2 */ @CheckReturnValue @@ -3356,16 +4265,16 @@ public final Single onTerminateDetach() { } /** - * Repeatedly re-subscribes to the current Single and emits each success value. + * Repeatedly re-subscribes to the current {@code Single} and emits each success value as a {@link Flowable} sequence. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer.
*
Scheduler:
*
{@code repeat} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new Flowable instance + * @return the new {@code Flowable} instance * @since 2.0 */ @BackpressureSupport(BackpressureKind.FULL) @@ -3377,17 +4286,18 @@ public final Flowable repeat() { } /** - * Re-subscribes to the current Single at most the given number of times and emits each success value. + * Re-subscribes to the current {@code Single} at most the given number of times and emits each success value as a {@link Flowable} sequence. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer.
*
Scheduler:
*
{@code repeat} does not operate by default on a particular {@link Scheduler}.
*
- * @param times the number of times to re-subscribe to the current Single - * @return the new Flowable instance + * @param times the number of times to re-subscribe to the current {@code Single} + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code times} is negative * @since 2.0 */ @BackpressureSupport(BackpressureKind.FULL) @@ -3399,11 +4309,11 @@ public final Flowable repeat(long times) { } /** - * Re-subscribes to the current Single if - * the Publisher returned by the handler function signals a value in response to a - * value signalled through the Flowable the handle receives. + * Re-subscribes to the current {@code Single} if + * the {@link Publisher} returned by the handler function signals a value in response to a + * value signaled through the {@link Flowable} the handler receives. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer. @@ -3411,34 +4321,37 @@ public final Flowable repeat(long times) { *
Scheduler:
*
{@code repeatWhen} does not operate by default on a particular {@link Scheduler}.
*
- * @param handler the function that is called with a Flowable that signals a value when the Single - * signalled a success value and returns a Publisher that has to signal a value to - * trigger a resubscription to the current Single, otherwise the terminal signal of - * the Publisher will be the terminal signal of the sequence as well. - * @return the new Flowable instance + * @param handler the function that is called with a {@code Flowable} that signals a value when the {@code Single} + * signaled a success value and returns a {@code Publisher} that has to signal a value to + * trigger a resubscription to the current {@code Single}, otherwise the terminal signal of + * the {@code Publisher} will be the terminal signal of the sequence as well. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code handler} is {@code null} * @since 2.0 */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable repeatWhen(@NonNull Function, ? extends Publisher> handler) { + public final Flowable repeatWhen(@NonNull Function, @NonNull ? extends Publisher<@NonNull ?>> handler) { return toFlowable().repeatWhen(handler); } /** - * Re-subscribes to the current Single until the given BooleanSupplier returns true. + * Re-subscribes to the current {@code Single} until the given {@link BooleanSupplier} returns {@code true} + * and emits the success items as a {@link Flowable} sequence. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer.
*
Scheduler:
*
{@code repeatUntil} does not operate by default on a particular {@link Scheduler}.
*
- * @param stop the BooleanSupplier called after the current Single succeeds and if returns false, - * the Single is re-subscribed; otherwise the sequence completes. - * @return the new Flowable instance + * @param stop the {@code BooleanSupplier} called after the current {@code Single} succeeds and if returns {@code false}, + * the {@code Single} is re-subscribed; otherwise the sequence completes. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code stop} is {@code null} * @since 2.0 */ @BackpressureSupport(BackpressureKind.FULL) @@ -3450,14 +4363,14 @@ public final Flowable repeatUntil(@NonNull BooleanSupplier stop) { } /** - * Repeatedly re-subscribes to the current Single indefinitely if it fails with an onError. + * Repeatedly re-subscribes to the current {@code Single} indefinitely if it fails with an {@code onError}. *

* *

*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new Single instance + * @return the new {@code Single} instance * @since 2.0 */ @CheckReturnValue @@ -3468,16 +4381,17 @@ public final Single retry() { } /** - * Repeatedly re-subscribe at most the specified times to the current Single - * if it fails with an onError. + * Repeatedly re-subscribe at most the specified times to the current {@code Single} + * if it fails with an {@code onError}. *

* *

*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
- * @param times the number of times to resubscribe if the current Single fails - * @return the new Single instance + * @param times the number of times to resubscribe if the current {@code Single} fails + * @return the new {@code Single} instance + * @throws IllegalArgumentException if {@code times} is negative * @since 2.0 */ @CheckReturnValue @@ -3488,17 +4402,18 @@ public final Single retry(long times) { } /** - * Re-subscribe to the current Single if the given predicate returns true when the Single fails - * with an onError. + * Re-subscribe to the current {@code Single} if the given predicate returns {@code true} when the {@code Single} fails + * with an {@code onError}. *

* *

*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
- * @param predicate the predicate called with the resubscription count and the failure Throwable - * and should return true if a resubscription should happen - * @return the new Single instance + * @param predicate the predicate called with the resubscription count and the failure {@link Throwable} + * and should return {@code true} if a resubscription should happen + * @return the new {@code Single} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -3509,8 +4424,8 @@ public final Single retry(@NonNull BiPredicate * *
@@ -3518,10 +4433,12 @@ public final Single retry(@NonNull BiPredicate{@code retry} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.1.8 - experimental - * @param times the number of times to resubscribe if the current Single fails - * @param predicate the predicate called with the failure Throwable - * and should return true if a resubscription should happen - * @return the new Single instance + * @param times the number of times to resubscribe if the current {@code Single} fails + * @param predicate the predicate called with the failure {@link Throwable} + * and should return {@code true} if a resubscription should happen + * @return the new {@code Single} instance + * @throws NullPointerException if {@code predicate} is {@code null} + * @throws IllegalArgumentException if {@code times} is negative * @since 2.2 */ @CheckReturnValue @@ -3532,17 +4449,18 @@ public final Single retry(long times, @NonNull Predicate p } /** - * Re-subscribe to the current Single if the given predicate returns true when the Single fails - * with an onError. + * Re-subscribe to the current {@code Single} if the given predicate returns {@code true} when the {@code Single} fails + * with an {@code onError}. *

* *

*
Scheduler:
*
{@code retry} does not operate by default on a particular {@link Scheduler}.
*
- * @param predicate the predicate called with the failure Throwable - * and should return true if a resubscription should happen - * @return the new Single instance + * @param predicate the predicate called with the failure {@link Throwable} + * and should return {@code true} if a resubscription should happen + * @return the new {@code Single} instance + * @throws NullPointerException if {@code predicate} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -3553,17 +4471,38 @@ public final Single retry(@NonNull Predicate predicate) { } /** - * Re-subscribes to the current Single if and when the Publisher returned by the handler + * Retries until the given stop function returns {@code true}. + *

+ * + *

+ *
Scheduler:
+ *
{@code retryUntil} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param stop the function that should return {@code true} to stop retrying + * @return the new {@code Single} instance + * @throws NullPointerException if {@code stop} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final Single retryUntil(@NonNull BooleanSupplier stop) { + Objects.requireNonNull(stop, "stop is null"); + return retry(Long.MAX_VALUE, Functions.predicateReverseFor(stop)); + } + + /** + * Re-subscribes to the current {@code Single} if and when the {@link Publisher} returned by the handler * function signals a value. *

* *

- * If the Publisher signals an {@code onComplete}, the resulting {@code Single} will signal a {@link NoSuchElementException}. + * If the {@code Publisher} signals an {@code onComplete}, the resulting {@code Single} will signal a {@link NoSuchElementException}. *

* Note that the inner {@code Publisher} returned by the handler function should signal * either {@code onNext}, {@code onError} or {@code onComplete} in response to the received - * {@code Throwable} to indicate the operator should retry or terminate. If the upstream to - * the operator is asynchronous, signaling onNext followed by onComplete immediately may + * {@link Throwable} to indicate the operator should retry or terminate. If the upstream to + * the operator is asynchronous, signaling {@code onNext} followed by {@code onComplete} immediately may * result in the sequence to be completed immediately. Similarly, if this inner * {@code Publisher} signals {@code onError} or {@code onComplete} while the upstream is * active, the sequence is terminated with the same signal immediately. @@ -3589,34 +4528,184 @@ public final Single retry(@NonNull Predicate predicate) { *

{@code retryWhen} does not operate by default on a particular {@link Scheduler}.
*
* - * @param handler the function that receives a Flowable of the error the Single emits and should - * return a Publisher that should signal a normal value (in response to the - * throwable the Flowable emits) to trigger a resubscription or signal an error to - * be the output of the resulting Single - * @return the new Single instance + * @param handler the function that receives a {@link Flowable} of the error the {@code Single} emits and should + * return a {@code Publisher} that should signal a normal value (in response to the + * throwable the {@code Flowable} emits) to trigger a resubscription or signal an error to + * be the output of the resulting {@code Single} + * @return the new {@code Single} instance + * @throws NullPointerException if {@code handler} is {@code null} */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single retryWhen(@NonNull Function, ? extends Publisher> handler) { + public final Single retryWhen(@NonNull Function, @NonNull ? extends Publisher<@NonNull ?>> handler) { return toSingle(toFlowable().retryWhen(handler)); } /** - * Subscribes to a Single but ignore its emission or notification. + * Wraps the given {@link SingleObserver}, catches any {@link RuntimeException}s thrown by its + * {@link SingleObserver#onSubscribe(Disposable)}, {@link SingleObserver#onSuccess(Object)} or + * {@link SingleObserver#onError(Throwable)} methods* and routes those to the global error handler + * via {@link RxJavaPlugins#onError(Throwable)}. + *

+ * By default, the {@code Single} protocol forbids the {@code onXXX} methods to throw, but some + * {@code SingleObserver} implementation may do it anyway, causing undefined behavior in the + * upstream. This method and the underlying safe wrapper ensures such misbehaving consumers don't + * disrupt the protocol. + *

+ *
Scheduler:
+ *
{@code safeSubscribe} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param observer the potentially misbehaving {@code SingleObserver} + * @throws NullPointerException if {@code observer} is {@code null} + * @see #subscribe(Consumer,Consumer) + * @since 3.0.0 + */ + @SchedulerSupport(SchedulerSupport.NONE) + public final void safeSubscribe(@NonNull SingleObserver observer) { + Objects.requireNonNull(observer, "observer is null"); + subscribe(new SafeSingleObserver<>(observer)); + } + + /** + * Returns a {@link Flowable} which first runs the other {@link CompletableSource} + * then the current {@code Single} if the other completed normally. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Flowable} honors the backpressure of the downstream consumer.
+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code CompletableSource} to run first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.FULL) + public final Flowable startWith(@NonNull CompletableSource other) { + Objects.requireNonNull(other, "other is null"); + return Flowable.concat(Completable.wrap(other).toFlowable(), toFlowable()); + } + + /** + * Returns a {@link Flowable} which first runs the other {@link SingleSource} + * then the current {@code Single} if the other succeeded normally. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Flowable} honors the backpressure of the downstream consumer.
+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code SingleSource} to run first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.FULL) + public final Flowable startWith(@NonNull SingleSource other) { + Objects.requireNonNull(other, "other is null"); + return Flowable.concat(Single.wrap(other).toFlowable(), toFlowable()); + } + + /** + * Returns a {@link Flowable} which first runs the other {@link MaybeSource} + * then the current {@code Single} if the other succeeded or completed normally. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Flowable} honors the backpressure of the downstream consumer.
+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code MaybeSource} to run first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + @BackpressureSupport(BackpressureKind.FULL) + public final Flowable startWith(@NonNull MaybeSource other) { + Objects.requireNonNull(other, "other is null"); + return Flowable.concat(Maybe.wrap(other).toFlowable(), toFlowable()); + } + + /** + * Returns an {@link Observable} which first delivers the events + * of the other {@link ObservableSource} then runs the current {@code Single}. + *

+ * + *

+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code ObservableSource} to run first + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.NONE) + public final Observable startWith(@NonNull ObservableSource other) { + Objects.requireNonNull(other, "other is null"); + return Observable.wrap(other).concatWith(this.toObservable()); + } + + /** + * Returns a {@link Flowable} which first delivers the events + * of the other {@link Publisher} then runs the current {@code Single}. + *

+ * + *

+ *
Backpressure:
+ *
The returned {@code Flowable} honors the backpressure of the downstream consumer + * and expects the other {@code Publisher} to honor it as well.
+ *
Scheduler:
+ *
{@code startWith} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param other the other {@code Publisher} to run first + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code other} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @BackpressureSupport(BackpressureKind.FULL) + @SchedulerSupport(SchedulerSupport.NONE) + public final Flowable startWith(@NonNull Publisher other) { + Objects.requireNonNull(other, "other is null"); + return toFlowable().startWith(other); + } + + /** + * Subscribes to a {@code Single} but ignore its emission or notification. *

* *

- * If the Single emits an error, it is wrapped into an + * If the {@code Single} emits an error, it is wrapped into an * {@link io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException OnErrorNotImplementedException} - * and routed to the RxJavaPlugins.onError handler. + * and routed to the {@link RxJavaPlugins#onError(Throwable)} handler. *

*
Scheduler:
*
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@link Disposable} reference can request the {@link Single} stop work. + * @return the new {@link Disposable} instance that can be used for disposing the subscription at any time * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, DisposableContainer) */ @SchedulerSupport(SchedulerSupport.NONE) @NonNull @@ -3625,7 +4714,7 @@ public final Disposable subscribe() { } /** - * Subscribes to a Single and provides a composite callback to handle the item it emits + * Subscribes to a {@code Single} and provides a composite callback to handle the item it emits * or any error notification it issues. *

* @@ -3635,17 +4724,18 @@ public final Disposable subscribe() { *

* * @param onCallback - * the callback that receives either the success value or the failure Throwable - * (whichever is not null) - * @return a {@link Disposable} reference can request the {@link Single} stop work. - * @see ReactiveX operators documentation: Subscribe + * the callback that receives either the success value or the failure {@link Throwable} + * (whichever is not {@code null}) + * @return the new {@link Disposable} instance that can be used for disposing the subscription at any time * @throws NullPointerException - * if {@code onCallback} is null + * if {@code onCallback} is {@code null} + * @see #subscribe(Consumer, Consumer, DisposableContainer) + * @see ReactiveX operators documentation: Subscribe */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Disposable subscribe(@NonNull BiConsumer onCallback) { + public final Disposable subscribe(@NonNull BiConsumer<@Nullable ? super T, @Nullable ? super Throwable> onCallback) { Objects.requireNonNull(onCallback, "onCallback is null"); BiConsumerSingleObserver observer = new BiConsumerSingleObserver<>(onCallback); @@ -3654,24 +4744,25 @@ public final Disposable subscribe(@NonNull BiConsumer * *

- * If the Single emits an error, it is wrapped into an + * If the {@code Single} emits an error, it is wrapped into an * {@link io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException OnErrorNotImplementedException} - * and routed to the RxJavaPlugins.onError handler. + * and routed to the {@link RxJavaPlugins#onError(Throwable)} handler. *

*
Scheduler:
*
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
*
* * @param onSuccess - * the {@code Consumer} you have designed to accept the emission from the Single - * @return a {@link Disposable} reference can request the {@link Single} stop work. + * the {@code Consumer} you have designed to accept the emission from the {@code Single} + * @return the new {@link Disposable} instance that can be used for disposing the subscription at any time * @throws NullPointerException - * if {@code onSuccess} is null + * if {@code onSuccess} is {@code null} * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, DisposableContainer) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -3681,7 +4772,7 @@ public final Disposable subscribe(@NonNull Consumer onSuccess) { } /** - * Subscribes to a Single and provides callbacks to handle the item it emits or any error notification it + * Subscribes to a {@code Single} and provides callbacks to handle the item it emits or any error notification it * issues. *

* @@ -3691,15 +4782,15 @@ public final Disposable subscribe(@NonNull Consumer onSuccess) { *

* * @param onSuccess - * the {@code Consumer} you have designed to accept the emission from the Single + * the {@code Consumer} you have designed to accept the emission from the {@code Single} * @param onError * the {@code Consumer} you have designed to accept any error notification from the - * Single - * @return a {@link Disposable} reference can request the {@link Single} stop work. - * @see ReactiveX operators documentation: Subscribe + * {@code Single} + * @return the new {@link Disposable} instance that can be used for disposing the subscription at any time * @throws NullPointerException - * if {@code onSuccess} is null, or - * if {@code onError} is null + * if {@code onSuccess} or {@code onError} is {@code null} + * @see ReactiveX operators documentation: Subscribe + * @see #subscribe(Consumer, Consumer, DisposableContainer) */ @CheckReturnValue @NonNull @@ -3713,6 +4804,44 @@ public final Disposable subscribe(@NonNull Consumer onSuccess, @NonNu return observer; } + /** + * Wraps the given onXXX callbacks into a {@link Disposable} {@link SingleObserver}, + * adds it to the given {@link DisposableContainer} and ensures, that if the upstream + * terminates or this particular {@code Disposable} is disposed, the {@code SingleObserver} is removed + * from the given container. + *

+ * The {@code SingleObserver} will be removed after the callback for the terminal event has been invoked. + *

+ *
Scheduler:
+ *
{@code subscribe} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param onSuccess the callback for upstream items + * @param onError the callback for an upstream error if any + * @param container the {@code DisposableContainer} (such as {@link CompositeDisposable}) to add and remove the + * created {@code Disposable} {@code SingleObserver} + * @return the {@code Disposable} that allows disposing the particular subscription. + * @throws NullPointerException + * if {@code onSuccess}, {@code onError} + * or {@code container} is {@code null} + * @since 3.1.0 + */ + @SchedulerSupport(SchedulerSupport.NONE) + @NonNull + public final Disposable subscribe( + @NonNull Consumer onSuccess, + @NonNull Consumer onError, + @NonNull DisposableContainer container) { + Objects.requireNonNull(onSuccess, "onSuccess is null"); + Objects.requireNonNull(onError, "onError is null"); + Objects.requireNonNull(container, "container is null"); + + DisposableAutoReleaseMultiObserver observer = new DisposableAutoReleaseMultiObserver<>( + container, onSuccess, onError, Functions.EMPTY_ACTION); + container.add(observer); + subscribe(observer); + return observer; + } + @SchedulerSupport(SchedulerSupport.NONE) @Override public final void subscribe(@NonNull SingleObserver observer) { @@ -3739,13 +4868,13 @@ public final void subscribe(@NonNull SingleObserver observer) { *

There is no need to call any of the plugin hooks on the current {@code Single} instance or * the {@code SingleObserver}; all hooks and basic safeguards have been * applied by {@link #subscribe(SingleObserver)} before this method gets called. - * @param observer the SingleObserver to handle, not null + * @param observer the {@code SingleObserver} to handle, not {@code null} */ protected abstract void subscribeActual(@NonNull SingleObserver observer); /** - * Subscribes a given SingleObserver (subclass) to this Single and returns the given - * SingleObserver as is. + * Subscribes a given {@link SingleObserver} (subclass) to this {@code Single} and returns the given + * {@code SingleObserver} as is. *

* *

Usage example: @@ -3763,10 +4892,10 @@ public final void subscribe(@NonNull SingleObserver observer) { *

Scheduler:
*
{@code subscribeWith} does not operate by default on a particular {@link Scheduler}.
*
- * @param the type of the SingleObserver to use and return - * @param observer the SingleObserver (subclass) to use and return, not null + * @param the type of the {@code SingleObserver} to use and return + * @param observer the {@code SingleObserver} (subclass) to use and return, not {@code null} * @return the input {@code observer} - * @throws NullPointerException if {@code observer} is null + * @throws NullPointerException if {@code observer} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -3778,17 +4907,18 @@ public final void subscribe(@NonNull SingleObserver observer) { } /** - * Asynchronously subscribes subscribers to this Single on the specified {@link Scheduler}. + * Asynchronously subscribes {@link SingleObserver}s to this {@code Single} on the specified {@link Scheduler}. *

- * + * *

*
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
+ *
You specify which {@code Scheduler} this operator will use.
*
* * @param scheduler - * the {@link Scheduler} to perform subscription actions on - * @return the source Single modified so that its subscriptions happen on the specified {@link Scheduler} + * the {@code Scheduler} to perform subscription actions on + * @return the new {@code Single} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @see ReactiveX operators documentation: SubscribeOn * @see RxJava Threading Examples * @see #observeOn @@ -3802,7 +4932,233 @@ public final Single subscribeOn(@NonNull Scheduler scheduler) { } /** - * Returns a Single that emits the item emitted by the source Single until a Completable terminates. Upon + * Measures the time (in milliseconds) between the subscription and success item emission + * of the current {@code Single} and signals it as a tuple ({@link Timed}) + * success value. + *

+ * + *

+ * If the current {@code Single} fails, the resulting {@code Single} will + * pass along the signal to the downstream. To measure the time to error, + * use {@link #materialize()} and apply {@link #timeInterval()}. + *

+ *
Scheduler:
+ *
{@code timeInterval} uses the {@code computation} {@link Scheduler} + * for determining the current time upon subscription and upon receiving the + * success item from the current {@code Single}.
+ *
+ * @return the new {@code Single} instance + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.COMPUTATION) + public final Single> timeInterval() { + return timeInterval(TimeUnit.MILLISECONDS, Schedulers.computation()); + } + + /** + * Measures the time (in milliseconds) between the subscription and success item emission + * of the current {@code Single} and signals it as a tuple ({@link Timed}) + * success value. + *

+ * + *

+ * If the current {@code Single} fails, the resulting {@code Single} will + * pass along the signal to the downstream. To measure the time to error, + * use {@link #materialize()} and apply {@link #timeInterval(Scheduler)}. + *

+ *
Scheduler:
+ *
{@code timeInterval} uses the provided {@link Scheduler} + * for determining the current time upon subscription and upon receiving the + * success item from the current {@code Single}.
+ *
+ * @param scheduler the {@code Scheduler} used for providing the current time + * @return the new {@code Single} instance + * @throws NullPointerException if {@code scheduler} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.CUSTOM) + public final Single> timeInterval(@NonNull Scheduler scheduler) { + return timeInterval(TimeUnit.MILLISECONDS, scheduler); + } + + /** + * Measures the time between the subscription and success item emission + * of the current {@code Single} and signals it as a tuple ({@link Timed}) + * success value. + *

+ * + *

+ * If the current {@code Single} fails, the resulting {@code Single} will + * pass along the signals to the downstream. To measure the time to error, + * use {@link #materialize()} and apply {@link #timeInterval(TimeUnit, Scheduler)}. + *

+ *
Scheduler:
+ *
{@code timeInterval} uses the {@code computation} {@link Scheduler} + * for determining the current time upon subscription and upon receiving the + * success item from the current {@code Single}.
+ *
+ * @param unit the time unit for measurement + * @return the new {@code Single} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.COMPUTATION) + public final Single> timeInterval(@NonNull TimeUnit unit) { + return timeInterval(unit, Schedulers.computation()); + } + + /** + * Measures the time between the subscription and success item emission + * of the current {@code Single} and signals it as a tuple ({@link Timed}) + * success value. + *

+ * + *

+ * If the current {@code Single} is empty or fails, the resulting {@code Single} will + * pass along the signals to the downstream. To measure the time to termination, + * use {@link #materialize()} and apply {@link #timeInterval(TimeUnit, Scheduler)}. + *

+ *
Scheduler:
+ *
{@code timeInterval} uses the provided {@link Scheduler} + * for determining the current time upon subscription and upon receiving the + * success item from the current {@code Single}.
+ *
+ * @param unit the time unit for measurement + * @param scheduler the {@code Scheduler} used for providing the current time + * @return the new {@code Single} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.CUSTOM) + public final Single> timeInterval(@NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + return RxJavaPlugins.onAssembly(new SingleTimeInterval<>(this, unit, scheduler, true)); + } + + /** + * Combines the success value from the current {@code Single} with the current time (in milliseconds) of + * its reception, using the {@code computation} {@link Scheduler} as time source, + * then signals them as a {@link Timed} instance. + *

+ * + *

+ * If the current {@code Single} is empty or fails, the resulting {@code Single} will + * pass along the signals to the downstream. To get the timestamp of the error, + * use {@link #materialize()} and apply {@link #timestamp()}. + *

+ *
Scheduler:
+ *
{@code timestamp} uses the {@code computation} {@code Scheduler} + * for determining the current time upon receiving the + * success item from the current {@code Single}.
+ *
+ * @return the new {@code Single} instance + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.COMPUTATION) + public final Single> timestamp() { + return timestamp(TimeUnit.MILLISECONDS, Schedulers.computation()); + } + + /** + * Combines the success value from the current {@code Single} with the current time (in milliseconds) of + * its reception, using the given {@link Scheduler} as time source, + * then signals them as a {@link Timed} instance. + *

+ * + *

+ * If the current {@code Single} is empty or fails, the resulting {@code Single} will + * pass along the signals to the downstream. To get the timestamp of the error, + * use {@link #materialize()} and apply {@link #timestamp(Scheduler)}. + *

+ *
Scheduler:
+ *
{@code timestamp} uses the provided {@code Scheduler} + * for determining the current time upon receiving the + * success item from the current {@code Single}.
+ *
+ * @param scheduler the {@code Scheduler} used for providing the current time + * @return the new {@code Single} instance + * @throws NullPointerException if {@code scheduler} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.CUSTOM) + public final Single> timestamp(@NonNull Scheduler scheduler) { + return timestamp(TimeUnit.MILLISECONDS, scheduler); + } + + /** + * Combines the success value from the current {@code Single} with the current time of + * its reception, using the {@code computation} {@link Scheduler} as time source, + * then signals it as a {@link Timed} instance. + *

+ * + *

+ * If the current {@code Single} is empty or fails, the resulting {@code Single} will + * pass along the signals to the downstream. To get the timestamp of the error, + * use {@link #materialize()} and apply {@link #timestamp(TimeUnit)}. + *

+ *
Scheduler:
+ *
{@code timestamp} uses the {@code computation} {@code Scheduler}, + * for determining the current time upon receiving the + * success item from the current {@code Single}.
+ *
+ * @param unit the time unit for measurement + * @return the new {@code Single} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.COMPUTATION) + public final Single> timestamp(@NonNull TimeUnit unit) { + return timestamp(unit, Schedulers.computation()); + } + + /** + * Combines the success value from the current {@code Single} with the current time of + * its reception, using the given {@link Scheduler} as time source, + * then signals it as a {@link Timed} instance. + *

+ * + *

+ * If the current {@code Single} is empty or fails, the resulting {@code Single} will + * pass along the signals to the downstream. To get the timestamp of the error, + * use {@link #materialize()} and apply {@link #timestamp(TimeUnit, Scheduler)}. + *

+ *
Scheduler:
+ *
{@code timestamp} uses the provided {@code Scheduler}, + * which is used for determining the current time upon receiving the + * success item from the current {@code Single}.
+ *
+ * @param unit the time unit for measurement + * @param scheduler the {@code Scheduler} used for providing the current time + * @return the new {@code Single} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @since 3.0.0 + */ + @CheckReturnValue + @NonNull + @SchedulerSupport(SchedulerSupport.CUSTOM) + public final Single> timestamp(@NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + return RxJavaPlugins.onAssembly(new SingleTimeInterval<>(this, unit, scheduler, false)); + } + + /** + * Returns a {@code Single} that emits the item emitted by the current {@code Single} until a {@link CompletableSource} terminates. Upon * termination of {@code other}, this will emit a {@link CancellationException} rather than go to * {@link SingleObserver#onSuccess(Object)}. *

@@ -3813,9 +5169,10 @@ public final Single subscribeOn(@NonNull Scheduler scheduler) { *

* * @param other - * the Completable whose termination will cause {@code takeUntil} to emit the item from the source - * Single - * @return a Single that emits the item emitted by the source Single until such time as {@code other} terminates. + * the {@code CompletableSource} whose termination will cause {@code takeUntil} to emit the item from the current + * {@code Single} + * @return the new {@code Single} that emits the item emitted by the current {@code Single} until such time as {@code other} terminates. + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: TakeUntil */ @CheckReturnValue @@ -3827,7 +5184,7 @@ public final Single takeUntil(@NonNull CompletableSource other) { } /** - * Returns a Single that emits the item emitted by the source Single until a Publisher emits an item. Upon + * Returns a {@code Single} that emits the item emitted by the current {@code Single} until a {@link Publisher} emits an item or completes. Upon * emission of an item from {@code other}, this will emit a {@link CancellationException} rather than go to * {@link SingleObserver#onSuccess(Object)}. *

@@ -3841,25 +5198,26 @@ public final Single takeUntil(@NonNull CompletableSource other) { *

* * @param other - * the Publisher whose first emitted item will cause {@code takeUntil} to emit the item from the source - * Single + * the {@code Publisher} whose first emitted item or completion will cause {@code takeUntil} to emit {@code CancellationException} + * if the current {@code Single} hasn't completed till then * @param * the type of items emitted by {@code other} - * @return a Single that emits the item emitted by the source Single until such time as {@code other} emits + * @return the new {@code Single} that emits the item emitted by the current {@code Single} until such time as {@code other} emits * its first item + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: TakeUntil */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single takeUntil(@NonNull Publisher other) { + public final <@NonNull E> Single takeUntil(@NonNull Publisher other) { Objects.requireNonNull(other, "other is null"); return RxJavaPlugins.onAssembly(new SingleTakeUntil<>(this, other)); } /** - * Returns a Single that emits the item emitted by the source Single until a second Single emits an item. Upon + * Returns a {@code Single} that emits the item emitted by the current {@code Single} until a second {@code Single} emits an item. Upon * emission of an item from {@code other}, this will emit a {@link CancellationException} rather than go to * {@link SingleObserver#onSuccess(Object)}. *

@@ -3870,32 +5228,35 @@ public final Single takeUntil(@NonNull Publisher other) { *

* * @param other - * the Single whose emitted item will cause {@code takeUntil} to emit the item from the source Single + * the {@code Single} whose emitted item will cause {@code takeUntil} to emit {@code CancellationException} + * if the current {@code Single} hasn't completed till then * @param * the type of item emitted by {@code other} - * @return a Single that emits the item emitted by the source Single until such time as {@code other} emits its item + * @return the new {@code Single} that emits the item emitted by the current {@code Single} until such time as {@code other} emits its item + * @throws NullPointerException if {@code other} is {@code null} * @see ReactiveX operators documentation: TakeUntil */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) - public final Single takeUntil(@NonNull SingleSource other) { + public final <@NonNull E> Single takeUntil(@NonNull SingleSource other) { Objects.requireNonNull(other, "other is null"); return takeUntil(new SingleToFlowable(other)); } /** - * Signals a TimeoutException if the current Single doesn't signal a success value within the + * Signals a {@link TimeoutException} if the current {@code Single} doesn't signal a success value within the * specified timeout window. *

- * + * *

*
Scheduler:
- *
{@code timeout} signals the TimeoutException on the {@code computation} {@link Scheduler}.
+ *
{@code timeout} signals the {@code TimeoutException} on the {@code computation} {@link Scheduler}.
*
* @param timeout the timeout amount * @param unit the time unit - * @return the new Single instance + * @return the new {@code Single} instance + * @throws NullPointerException if {@code unit} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -3906,19 +5267,20 @@ public final Single timeout(long timeout, @NonNull TimeUnit unit) { } /** - * Signals a TimeoutException if the current Single doesn't signal a success value within the + * Signals a {@link TimeoutException} if the current {@code Single} doesn't signal a success value within the * specified timeout window. *

* *

*
Scheduler:
- *
{@code timeout} signals the TimeoutException on the {@link Scheduler} you specify.
+ *
{@code timeout} signals the {@code TimeoutException} on the {@link Scheduler} you specify.
*
* @param timeout the timeout amount * @param unit the time unit - * @param scheduler the target scheduler where the timeout is awaited and the TimeoutException - * signalled - * @return the new Single instance + * @param scheduler the target {@code Scheduler} where the timeout is awaited and the {@code TimeoutException} + * signaled + * @return the new {@code Single} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @since 2.0 */ @CheckReturnValue @@ -3929,67 +5291,66 @@ public final Single timeout(long timeout, @NonNull TimeUnit unit, @NonNull Sc } /** - * Runs the current Single and if it doesn't signal within the specified timeout window, it is - * disposed and the other SingleSource subscribed to. + * Runs the current {@code Single} and if it doesn't signal within the specified timeout window, it is + * disposed and the other {@link SingleSource} subscribed to. *

* *

*
Scheduler:
- *
{@code timeout} subscribes to the other SingleSource on the {@link Scheduler} you specify.
+ *
{@code timeout} subscribes to the other {@code SingleSource} on the {@link Scheduler} you specify.
*
* @param timeout the timeout amount * @param unit the time unit - * @param scheduler the scheduler where the timeout is awaited and the subscription to other happens - * @param other the other SingleSource that gets subscribed to if the current Single times out - * @return the new Single instance + * @param scheduler the {@code Scheduler} where the timeout is awaited and the subscription to other happens + * @param fallback the other {@code SingleSource} that gets subscribed to if the current {@code Single} times out + * @return the new {@code Single} instance + * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code fallback} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Single timeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull SingleSource other) { - Objects.requireNonNull(other, "other is null"); - return timeout0(timeout, unit, scheduler, other); + public final Single timeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull SingleSource fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return timeout0(timeout, unit, scheduler, fallback); } /** - * Runs the current Single and if it doesn't signal within the specified timeout window, it is - * disposed and the other SingleSource subscribed to. + * Runs the current {@code Single} and if it doesn't signal within the specified timeout window, it is + * disposed and the other {@link SingleSource} subscribed to. *

* *

*
Scheduler:
- *
{@code timeout} subscribes to the other SingleSource on + *
{@code timeout} subscribes to the other {@code SingleSource} on * the {@code computation} {@link Scheduler}.
*
* @param timeout the timeout amount * @param unit the time unit - * @param other the other SingleSource that gets subscribed to if the current Single times out - * @return the new Single instance + * @param fallback the other {@code SingleSource} that gets subscribed to if the current {@code Single} times out + * @return the new {@code Single} instance * @throws NullPointerException - * if other is null, or - * if unit is null, or - * if scheduler is null + * if {@code fallback} or {@code unit} is {@code null} * @since 2.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.COMPUTATION) - public final Single timeout(long timeout, @NonNull TimeUnit unit, @NonNull SingleSource other) { - Objects.requireNonNull(other, "other is null"); - return timeout0(timeout, unit, Schedulers.computation(), other); + public final Single timeout(long timeout, @NonNull TimeUnit unit, @NonNull SingleSource fallback) { + Objects.requireNonNull(fallback, "fallback is null"); + return timeout0(timeout, unit, Schedulers.computation(), fallback); } - private Single timeout0(final long timeout, final TimeUnit unit, final Scheduler scheduler, final SingleSource other) { + private Single timeout0(final long timeout, final TimeUnit unit, final Scheduler scheduler, final SingleSource fallback) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new SingleTimeout<>(this, timeout, unit, scheduler, other)); + return RxJavaPlugins.onAssembly(new SingleTimeout<>(this, timeout, unit, scheduler, fallback)); } /** * Calls the specified converter function during assembly time and returns its resulting value. *

- * + * *

* This allows fluent conversion to any other type. *

@@ -3998,9 +5359,9 @@ private Single timeout0(final long timeout, final TimeUnit unit, final Schedu *
*

History: 2.1.7 - experimental * @param the resulting object type - * @param converter the function that receives the current Single instance and returns a value + * @param converter the function that receives the current {@code Single} instance and returns a value * @return the converted value - * @throws NullPointerException if converter is null + * @throws NullPointerException if {@code converter} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -4010,7 +5371,7 @@ public final R to(@NonNull SingleConverter converter) { } /** - * Returns a {@link Completable} that ignores the success value of this {@link Single} + * Returns a {@link Completable} that ignores the success value of this {@code Single} * and signals {@code onComplete} instead. *

* @@ -4019,8 +5380,7 @@ public final R to(@NonNull SingleConverter converter) { *

{@code ignoreElement} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@link Completable} that signals {@code onComplete} on it's observer when the source {@link Single} - * calls {@code onSuccess}. + * @return the new {@code Completable} instance * @since 2.1.13 */ @CheckReturnValue @@ -4031,9 +5391,9 @@ public final Completable ignoreElement() { } /** - * Converts this Single into a {@link Flowable}. + * Converts this {@code Single} into a {@link Flowable}. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer.
@@ -4041,7 +5401,7 @@ public final Completable ignoreElement() { *
{@code toFlowable} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@link Flowable} that emits a single item T or an error. + * @return the new {@code Flowable} instance */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @@ -4058,32 +5418,34 @@ public final Flowable toFlowable() { /** * Returns a {@link Future} representing the single value emitted by this {@code Single}. *

- * + * + *

+ * Cancelling the {@code Future} will cancel the subscription to the current {@code Single}. *

*
Scheduler:
*
{@code toFuture} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@link Future} that expects a single item to be emitted by this {@code Single} + * @return the new {@code Future} instance * @see ReactiveX documentation: To */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final Future toFuture() { - return subscribeWith(new FutureSingleObserver<>()); + return subscribeWith(new FutureMultiObserver<>()); } /** - * Converts this Single into a {@link Maybe}. + * Converts this {@code Single} into a {@link Maybe}. *

- * + * *

*
Scheduler:
*
{@code toMaybe} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a {@link Maybe} that emits a single item T or an error. + * @return the new {@code Maybe} instance */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -4096,15 +5458,15 @@ public final Maybe toMaybe() { return RxJavaPlugins.onAssembly(new MaybeFromSingle<>(this)); } /** - * Converts this Single into an {@link Observable}. + * Converts this {@code Single} into an {@link Observable}. *

- * + * *

*
Scheduler:
*
{@code toObservable} does not operate by default on a particular {@link Scheduler}.
*
* - * @return an {@link Observable} that emits a single item T or an error. + * @return the new {@code Observable} instance */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -4118,18 +5480,18 @@ public final Observable toObservable() { } /** - * Returns a Single which makes sure when a SingleObserver disposes the Disposable, - * that call is propagated up on the specified scheduler. + * Returns a {@code Single} which makes sure when a {@link SingleObserver} disposes the {@link Disposable}, + * that call is propagated up on the specified {@link Scheduler}. *

* *

*
Scheduler:
- *
{@code unsubscribeOn} calls dispose() of the upstream on the {@link Scheduler} you specify.
+ *
{@code unsubscribeOn} calls {@code dispose()} of the upstream on the {@code Scheduler} you specify.
*
*

History: 2.0.9 - experimental * @param scheduler the target scheduler where to execute the disposal - * @return the new Single instance - * @throws NullPointerException if scheduler is null + * @return the new {@code Single} instance + * @throws NullPointerException if {@code scheduler} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -4141,8 +5503,8 @@ public final Single unsubscribeOn(@NonNull Scheduler scheduler) { } /** - * Returns a Single that emits the result of applying a specified function to the pair of items emitted by - * the source Single and another specified Single. + * Returns a {@code Single} that emits the result of applying a specified function to the pair of items emitted by + * the current {@code Single} and another specified {@link SingleSource}. *

* *

@@ -4151,22 +5513,23 @@ public final Single unsubscribeOn(@NonNull Scheduler scheduler) { *
* * @param - * the type of items emitted by the {@code other} Single + * the type of items emitted by the {@code other} {@code Single} * @param - * the type of items emitted by the resulting Single + * the type of items emitted by the resulting {@code Single} * @param other - * the other SingleSource + * the other {@code SingleSource} * @param zipper - * a function that combines the pairs of items from the two SingleSources to generate the items to - * be emitted by the resulting Single - * @return a Single that pairs up values from the source Single and the {@code other} SingleSource + * a function that combines the pairs of items from the two {@code SingleSource}s to generate the items to + * be emitted by the resulting {@code Single} + * @return the new {@code Single} that pairs up values from the current {@code Single} and the {@code other} {@code SingleSource} * and emits the results of {@code zipFunction} applied to these pairs + * @throws NullPointerException if {@code other} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Single zipWith(@NonNull SingleSource other, @NonNull BiFunction zipper) { + public final <@NonNull U, @NonNull R> Single zipWith(@NonNull SingleSource other, @NonNull BiFunction zipper) { return zip(this, other, zipper); } @@ -4174,15 +5537,14 @@ public final Single zipWith(@NonNull SingleSource other, @NonNull B // Fluent test support, super handy and reduces test preparation boilerplate // ------------------------------------------------------------------------- /** - * Creates a TestObserver and subscribes - * it to this Single. + * Creates a {@link TestObserver} and subscribes it to this {@code Single}. *

* *

*
Scheduler:
*
{@code test} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new TestObserver instance + * @return the new {@code TestObserver} instance * @since 2.0 */ @CheckReturnValue @@ -4195,16 +5557,16 @@ public final TestObserver test() { } /** - * Creates a TestObserver optionally in cancelled state, then subscribes it to this Single. + * Creates a {@link TestObserver} optionally in cancelled state, then subscribes it to this {@code Single}. *

* *

*
Scheduler:
*
{@code test} does not operate by default on a particular {@link Scheduler}.
*
- * @param dispose if true, the TestObserver will be cancelled before subscribing to this - * Single. - * @return the new TestObserver instance + * @param dispose if {@code true}, the {@code TestObserver} will be cancelled before subscribing to this + * {@code Single}. + * @return the new {@code TestObserver} instance * @since 2.0 */ @CheckReturnValue @@ -4236,7 +5598,7 @@ private static Single toSingle(@NonNull Flowable source) { * *

* Note that the operator takes an already instantiated, running or terminated {@code CompletionStage}. - * If the optional is to be created per consumer upon subscription, use {@link #defer(Supplier)} + * If the {@code CompletionStage} is to be created per consumer upon subscription, use {@link #defer(Supplier)} * around {@code fromCompletionStage}: *


      * Single.defer(() -> Single.fromCompletionStage(createCompletionStage()));
@@ -4251,21 +5613,22 @@ private static  Single toSingle(@NonNull Flowable source) {
      *  
Scheduler:
*
{@code fromCompletionStage} does not operate by default on a particular {@link Scheduler}.
*
- * @param the element type of the CompletionStage - * @param stage the CompletionStage to convert to Single and signal its success value or error - * @return the new Single instance + * @param the element type of the {@code CompletionStage} + * @param stage the {@code CompletionStage} to convert to {@code Single} and signal its success value or error + * @return the new {@code Single} instance + * @throws NullPointerException if {@code stage} is {@code null} * @since 3.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static Single<@NonNull T> fromCompletionStage(@NonNull CompletionStage stage) { + public static <@NonNull T> Single<@NonNull T> fromCompletionStage(@NonNull CompletionStage stage) { Objects.requireNonNull(stage, "stage is null"); return RxJavaPlugins.onAssembly(new SingleFromCompletionStage<>(stage)); } /** - * Maps the upstream success value into an {@link Optional} and emits the contained item if not empty. + * Maps the upstream success value into an {@link Optional} and emits the contained item if not empty as a {@link Maybe}. *

* * @@ -4273,10 +5636,11 @@ private static Single toSingle(@NonNull Flowable source) { *

Scheduler:
*
{@code mapOptional} does not operate by default on a particular {@link Scheduler}.
*
- * @param the non-null output type + * @param the non-{@code null} output type * @param mapper the function that receives the upstream success item and should return a non-empty {@code Optional} * to emit as the success output or an empty {@code Optional} to complete the {@code Maybe} - * @return the new Maybe instance + * @return the new {@code Maybe} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @since 3.0.0 * @see #map(Function) * @see #filter(Predicate) @@ -4303,7 +5667,7 @@ private static Single toSingle(@NonNull Flowable source) { *
Scheduler:
*
{@code toCompletionStage} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new CompletionStage instance + * @return the new {@code CompletionStage} instance * @since 3.0.0 */ @CheckReturnValue @@ -4318,7 +5682,7 @@ public final CompletionStage toCompletionStage() { * items to the downstream consumer as a {@link Flowable}. * *

- * The operator closes the {@code Stream} upon cancellation and when it terminates. Exceptions raised when + * The operator closes the {@code Stream} upon cancellation and when it terminates. The exceptions raised when * closing a {@code Stream} are routed to the global error handler ({@link RxJavaPlugins#onError(Throwable)}. * If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #flattenAsFlowable(Function)}: *


@@ -4342,7 +5706,8 @@ public final CompletionStage toCompletionStage() {
      * @param  the element type of the {@code Stream} and the output {@code Flowable}
      * @param mapper the function that receives the upstream success item and should
      * return a {@code Stream} of values to emit.
-     * @return the new Flowable instance
+     * @return the new {@code Flowable} instance
+     * @throws NullPointerException if {@code mapper} is {@code null}
      * @since 3.0.0
      * @see #flattenAsFlowable(Function)
      * @see #flattenStreamAsObservable(Function)
@@ -4351,7 +5716,7 @@ public final CompletionStage toCompletionStage() {
     @SchedulerSupport(SchedulerSupport.NONE)
     @BackpressureSupport(BackpressureKind.FULL)
     @NonNull
-    public final  Flowable flattenStreamAsFlowable(@NonNull Function> mapper) {
+    public final <@NonNull R> Flowable flattenStreamAsFlowable(@NonNull Function> mapper) {
         Objects.requireNonNull(mapper, "mapper is null");
         return RxJavaPlugins.onAssembly(new SingleFlattenStreamAsFlowable<>(this, mapper));
     }
@@ -4360,11 +5725,11 @@ public final  Flowable flattenStreamAsFlowable(@NonNull Function
-     * 
+     * 
      * 

- * The operator closes the {@code Stream} upon cancellation and when it terminates. Exceptions raised when + * The operator closes the {@code Stream} upon cancellation and when it terminates. The exceptions raised when * closing a {@code Stream} are routed to the global error handler ({@link RxJavaPlugins#onError(Throwable)}. - * If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #flattenAsFlowable(Function)}: + * If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #flattenAsObservable(Function)}: *


      * source.flattenAsObservable(item -> createStream(item)::iterator);
      * 
@@ -4383,7 +5748,8 @@ public final Flowable flattenStreamAsFlowable(@NonNull Function the element type of the {@code Stream} and the output {@code Observable} * @param mapper the function that receives the upstream success item and should * return a {@code Stream} of values to emit. - * @return the new Observable instance + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code mapper} is {@code null} * @since 3.0.0 * @see #flattenAsObservable(Function) * @see #flattenStreamAsFlowable(Function) @@ -4391,7 +5757,7 @@ public final Flowable flattenStreamAsFlowable(@NonNull Function Observable flattenStreamAsObservable(@NonNull Function> mapper) { + public final <@NonNull R> Observable flattenStreamAsObservable(@NonNull Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new SingleFlattenStreamAsObservable<>(this, mapper)); } diff --git a/src/main/java/io/reactivex/rxjava3/core/SingleConverter.java b/src/main/java/io/reactivex/rxjava3/core/SingleConverter.java index eb100b6c87a..960a17d9d51 100644 --- a/src/main/java/io/reactivex/rxjava3/core/SingleConverter.java +++ b/src/main/java/io/reactivex/rxjava3/core/SingleConverter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,13 +24,12 @@ * @since 2.2 */ @FunctionalInterface -public interface SingleConverter { +public interface SingleConverter<@NonNull T, @NonNull R> { /** * Applies a function to the upstream {@link Single} and returns a converted value of type {@code R}. * * @param upstream the upstream {@code Single} instance * @return the converted value */ - @NonNull R apply(@NonNull Single upstream); } diff --git a/src/main/java/io/reactivex/rxjava3/core/SingleEmitter.java b/src/main/java/io/reactivex/rxjava3/core/SingleEmitter.java index bb3768243d6..4b18a816445 100644 --- a/src/main/java/io/reactivex/rxjava3/core/SingleEmitter.java +++ b/src/main/java/io/reactivex/rxjava3/core/SingleEmitter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,7 +15,7 @@ import io.reactivex.rxjava3.annotations.*; import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.functions.Cancellable; +import io.reactivex.rxjava3.functions.*; /** * Abstraction over an RxJava {@link SingleObserver} that allows associating @@ -47,7 +47,7 @@ * * @param the value type to emit */ -public interface SingleEmitter { +public interface SingleEmitter<@NonNull T> { /** * Signal a success value. diff --git a/src/main/java/io/reactivex/rxjava3/core/SingleObserver.java b/src/main/java/io/reactivex/rxjava3/core/SingleObserver.java index d2d788d38f4..a110d4bcff3 100644 --- a/src/main/java/io/reactivex/rxjava3/core/SingleObserver.java +++ b/src/main/java/io/reactivex/rxjava3/core/SingleObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -50,7 +50,7 @@ * the type of item the SingleObserver expects to observe * @since 2.0 */ -public interface SingleObserver { +public interface SingleObserver<@NonNull T> { /** * Provides the {@link SingleObserver} with the means of cancelling (disposing) the diff --git a/src/main/java/io/reactivex/rxjava3/core/SingleOnSubscribe.java b/src/main/java/io/reactivex/rxjava3/core/SingleOnSubscribe.java index 7a6a5adf680..e8b9e89f8ba 100644 --- a/src/main/java/io/reactivex/rxjava3/core/SingleOnSubscribe.java +++ b/src/main/java/io/reactivex/rxjava3/core/SingleOnSubscribe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,19 +10,20 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.core; import io.reactivex.rxjava3.annotations.NonNull; /** * A functional interface that has a {@code subscribe()} method that receives - * an instance of a {@link SingleEmitter} instance that allows pushing + * a {@link SingleEmitter} instance that allows pushing * an event in a cancellation-safe manner. * * @param the value type pushed */ @FunctionalInterface -public interface SingleOnSubscribe { +public interface SingleOnSubscribe<@NonNull T> { /** * Called for each {@link SingleObserver} that subscribes. diff --git a/src/main/java/io/reactivex/rxjava3/core/SingleOperator.java b/src/main/java/io/reactivex/rxjava3/core/SingleOperator.java index de2f38f23d4..3b9c4a53c59 100644 --- a/src/main/java/io/reactivex/rxjava3/core/SingleOperator.java +++ b/src/main/java/io/reactivex/rxjava3/core/SingleOperator.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ * @param the value type of the upstream */ @FunctionalInterface -public interface SingleOperator { +public interface SingleOperator<@NonNull Downstream, @NonNull Upstream> { /** * Applies a function to the child {@link SingleObserver} and returns a new parent {@code SingleObserver}. * @param observer the child {@code SingleObserver} instance diff --git a/src/main/java/io/reactivex/rxjava3/core/SingleSource.java b/src/main/java/io/reactivex/rxjava3/core/SingleSource.java index b4c923905db..16147fd55b0 100644 --- a/src/main/java/io/reactivex/rxjava3/core/SingleSource.java +++ b/src/main/java/io/reactivex/rxjava3/core/SingleSource.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.core; import io.reactivex.rxjava3.annotations.NonNull; @@ -25,7 +26,7 @@ * @since 2.0 */ @FunctionalInterface -public interface SingleSource { +public interface SingleSource<@NonNull T> { /** * Subscribes the given {@link SingleObserver} to this {@link SingleSource} instance. diff --git a/src/main/java/io/reactivex/rxjava3/core/SingleTransformer.java b/src/main/java/io/reactivex/rxjava3/core/SingleTransformer.java index 1f0d478a0e2..3ece315f978 100644 --- a/src/main/java/io/reactivex/rxjava3/core/SingleTransformer.java +++ b/src/main/java/io/reactivex/rxjava3/core/SingleTransformer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ * @param the downstream value type */ @FunctionalInterface -public interface SingleTransformer { +public interface SingleTransformer<@NonNull Upstream, @NonNull Downstream> { /** * Applies a function to the upstream {@link Single} and returns a {@link SingleSource} with * optionally different element type. diff --git a/src/main/java/io/reactivex/rxjava3/core/package-info.java b/src/main/java/io/reactivex/rxjava3/core/package-info.java index 91717d01781..ee76f76a64a 100644 --- a/src/main/java/io/reactivex/rxjava3/core/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/core/package-info.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + /** * Base reactive classes: {@link io.reactivex.rxjava3.core.Flowable}, {@link io.reactivex.rxjava3.core.Observable}, * {@link io.reactivex.rxjava3.core.Single}, {@link io.reactivex.rxjava3.core.Maybe} and diff --git a/src/main/java/io/reactivex/rxjava3/disposables/ActionDisposable.java b/src/main/java/io/reactivex/rxjava3/disposables/ActionDisposable.java index 32ad4786566..4caad11d792 100644 --- a/src/main/java/io/reactivex/rxjava3/disposables/ActionDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/disposables/ActionDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.disposables; import io.reactivex.rxjava3.annotations.NonNull; diff --git a/src/main/java/io/reactivex/rxjava3/disposables/AutoCloseableDisposable.java b/src/main/java/io/reactivex/rxjava3/disposables/AutoCloseableDisposable.java index 08cbe9cd99c..34cdaed0eb6 100644 --- a/src/main/java/io/reactivex/rxjava3/disposables/AutoCloseableDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/disposables/AutoCloseableDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/disposables/CompositeDisposable.java b/src/main/java/io/reactivex/rxjava3/disposables/CompositeDisposable.java index eaf067c1777..bcf28ec148d 100644 --- a/src/main/java/io/reactivex/rxjava3/disposables/CompositeDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/disposables/CompositeDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,17 +10,19 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.disposables; import java.util.*; -import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.annotations.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.internal.util.*; /** - * A disposable container that can hold onto multiple other disposables and - * offers O(1) add and removal complexity. + * A disposable container that can hold onto multiple other {@link Disposable}s and + * offers O(1) time complexity for {@link #add(Disposable)}, {@link #remove(Disposable)} and {@link #delete(Disposable)} + * operations. */ public final class CompositeDisposable implements Disposable, DisposableContainer { @@ -29,14 +31,14 @@ public final class CompositeDisposable implements Disposable, DisposableContaine volatile boolean disposed; /** - * Creates an empty CompositeDisposable. + * Creates an empty {@code CompositeDisposable}. */ public CompositeDisposable() { } /** - * Creates a CompositeDisposables with the given array of initial elements. - * @param disposables the array of Disposables to start with + * Creates a {@code CompositeDisposable} with the given array of initial {@link Disposable} elements. + * @param disposables the array of {@code Disposable}s to start with * @throws NullPointerException if {@code disposables} or any of its array items is {@code null} */ public CompositeDisposable(@NonNull Disposable... disposables) { @@ -49,8 +51,8 @@ public CompositeDisposable(@NonNull Disposable... disposables) { } /** - * Creates a CompositeDisposables with the given Iterable sequence of initial elements. - * @param disposables the Iterable sequence of Disposables to start with + * Creates a {@code CompositeDisposable} with the given {@link Iterable} sequence of initial {@link Disposable} elements. + * @param disposables the {@code Iterable} sequence of {@code Disposable} to start with * @throws NullPointerException if {@code disposables} or any of its items is {@code null} */ public CompositeDisposable(@NonNull Iterable disposables) { @@ -86,10 +88,10 @@ public boolean isDisposed() { } /** - * Adds a disposable to this container or disposes it if the + * Adds a {@link Disposable} to this container or disposes it if the * container has been disposed. - * @param disposable the disposable to add, not null - * @return true if successful, false if this container has been disposed + * @param disposable the {@code Disposable} to add, not {@code null} + * @return {@code true} if successful, {@code false} if this container has been disposed * @throws NullPointerException if {@code disposable} is {@code null} */ @Override @@ -113,10 +115,10 @@ public boolean add(@NonNull Disposable disposable) { } /** - * Atomically adds the given array of Disposables to the container or + * Atomically adds the given array of {@link Disposable}s to the container or * disposes them all if the container has been disposed. - * @param disposables the array of Disposables - * @return true if the operation was successful, false if the container has been disposed + * @param disposables the array of {@code Disposable}s + * @return {@code true} if the operation was successful, {@code false} if the container has been disposed * @throws NullPointerException if {@code disposables} or any of its array items is {@code null} */ public boolean addAll(@NonNull Disposable... disposables) { @@ -144,10 +146,11 @@ public boolean addAll(@NonNull Disposable... disposables) { } /** - * Removes and disposes the given disposable if it is part of this + * Removes and disposes the given {@link Disposable} if it is part of this * container. - * @param disposable the disposable to remove and dispose, not null - * @return true if the operation was successful + * @param disposable the disposable to remove and dispose, not {@code null} + * @return {@code true} if the operation was successful + * @throws NullPointerException if {@code disposable} is {@code null} */ @Override public boolean remove(@NonNull Disposable disposable) { @@ -159,15 +162,15 @@ public boolean remove(@NonNull Disposable disposable) { } /** - * Removes (but does not dispose) the given disposable if it is part of this + * Removes (but does not dispose) the given {@link Disposable} if it is part of this * container. - * @param disposable the disposable to remove, not null - * @return true if the operation was successful + * @param disposable the disposable to remove, not {@code null} + * @return {@code true} if the operation was successful * @throws NullPointerException if {@code disposable} is {@code null} */ @Override public boolean delete(@NonNull Disposable disposable) { - Objects.requireNonNull(disposable, "disposables is null"); + Objects.requireNonNull(disposable, "disposable is null"); if (disposed) { return false; } @@ -185,7 +188,7 @@ public boolean delete(@NonNull Disposable disposable) { } /** - * Atomically clears the container, then disposes all the previously contained Disposables. + * Atomically clears the container, then disposes all the previously contained {@link Disposable}s. */ public void clear() { if (disposed) { @@ -205,8 +208,8 @@ public void clear() { } /** - * Returns the number of currently held Disposables. - * @return the number of currently held Disposables + * Returns the number of currently held {@link Disposable}s. + * @return the number of currently held {@code Disposable}s */ public int size() { if (disposed) { @@ -222,11 +225,11 @@ public int size() { } /** - * Dispose the contents of the OpenHashSet by suppressing non-fatal - * Throwables till the end. - * @param set the OpenHashSet to dispose elements of + * Dispose the contents of the {@link OpenHashSet} by suppressing non-fatal + * {@link Throwable}s till the end. + * @param set the {@code OpenHashSet} to dispose elements of */ - void dispose(OpenHashSet set) { + void dispose(@Nullable OpenHashSet set) { if (set == null) { return; } diff --git a/src/main/java/io/reactivex/rxjava3/disposables/Disposable.java b/src/main/java/io/reactivex/rxjava3/disposables/Disposable.java index d71a452cb11..845d603171c 100644 --- a/src/main/java/io/reactivex/rxjava3/disposables/Disposable.java +++ b/src/main/java/io/reactivex/rxjava3/disposables/Disposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.disposables; import io.reactivex.rxjava3.annotations.NonNull; @@ -39,8 +40,8 @@ public interface Disposable { /** * Construct a {@code Disposable} by wrapping a {@link Runnable} that is * executed exactly once when the {@code Disposable} is disposed. - * @param run the Runnable to wrap - * @return the new Disposable instance + * @param run the {@code Runnable} to wrap + * @return the new {@code Disposable} instance * @throws NullPointerException if {@code run} is {@code null} * @since 3.0.0 */ @@ -53,8 +54,8 @@ static Disposable fromRunnable(@NonNull Runnable run) { /** * Construct a {@code Disposable} by wrapping a {@link Action} that is * executed exactly once when the {@code Disposable} is disposed. - * @param action the Action to wrap - * @return the new Disposable instance + * @param action the {@code Action} to wrap + * @return the new {@code Disposable} instance * @throws NullPointerException if {@code action} is {@code null} * @since 3.0.0 */ @@ -69,8 +70,8 @@ static Disposable fromAction(@NonNull Action action) { * cancelled exactly once when the {@code Disposable} is disposed. *

* The {@code Future} is cancelled with {@code mayInterruptIfRunning == true}. - * @param future the Future to wrap - * @return the new Disposable instance + * @param future the {@code Future} to wrap + * @return the new {@code Disposable} instance * @throws NullPointerException if {@code future} is {@code null} * @see #fromFuture(Future, boolean) * @since 3.0.0 @@ -84,9 +85,9 @@ static Disposable fromFuture(@NonNull Future future) { /** * Construct a {@code Disposable} by wrapping a {@link Future} that is * cancelled exactly once when the {@code Disposable} is disposed. - * @param future the Future to wrap + * @param future the {@code Future} to wrap * @param allowInterrupt if true, the future cancel happens via {@code Future.cancel(true)} - * @return the new Disposable instance + * @return the new {@code Disposable} instance * @throws NullPointerException if {@code future} is {@code null} * @since 3.0.0 */ @@ -99,8 +100,8 @@ static Disposable fromFuture(@NonNull Future future, boolean allowInterrupt) /** * Construct a {@code Disposable} by wrapping a {@link Subscription} that is * cancelled exactly once when the {@code Disposable} is disposed. - * @param subscription the Runnable to wrap - * @return the new Disposable instance + * @param subscription the {@code Runnable} to wrap + * @return the new {@code Disposable} instance * @throws NullPointerException if {@code subscription} is {@code null} * @since 3.0.0 */ @@ -113,8 +114,8 @@ static Disposable fromSubscription(@NonNull Subscription subscription) { /** * Construct a {@code Disposable} by wrapping an {@link AutoCloseable} that is * closed exactly once when the {@code Disposable} is disposed. - * @param autoCloseable the AutoCloseable to wrap - * @return the new Disposable instance + * @param autoCloseable the {@code AutoCloseable} to wrap + * @return the new {@code Disposable} instance * @throws NullPointerException if {@code autoCloseable} is {@code null} * @since 3.0.0 */ @@ -127,8 +128,8 @@ static Disposable fromAutoCloseable(@NonNull AutoCloseable autoCloseable) { /** * Construct an {@link AutoCloseable} by wrapping a {@code Disposable} that is * disposed when the returned {@code AutoCloseable} is closed. - * @param disposable the Disposable instance - * @return the new AutoCloseable instance + * @param disposable the {@code Disposable} instance + * @return the new {@code AutoCloseable} instance * @throws NullPointerException if {@code disposable} is {@code null} * @since 3.0.0 */ diff --git a/src/main/java/io/reactivex/rxjava3/disposables/DisposableContainer.java b/src/main/java/io/reactivex/rxjava3/disposables/DisposableContainer.java index d7099fbadc2..49311e40829 100644 --- a/src/main/java/io/reactivex/rxjava3/disposables/DisposableContainer.java +++ b/src/main/java/io/reactivex/rxjava3/disposables/DisposableContainer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/disposables/FutureDisposable.java b/src/main/java/io/reactivex/rxjava3/disposables/FutureDisposable.java index 9649bcd7d3c..d8f70ff6554 100644 --- a/src/main/java/io/reactivex/rxjava3/disposables/FutureDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/disposables/FutureDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.disposables; import java.util.concurrent.Future; diff --git a/src/main/java/io/reactivex/rxjava3/disposables/ReferenceDisposable.java b/src/main/java/io/reactivex/rxjava3/disposables/ReferenceDisposable.java index eea584ab0b7..55bb24a2687 100644 --- a/src/main/java/io/reactivex/rxjava3/disposables/ReferenceDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/disposables/ReferenceDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/disposables/RunnableDisposable.java b/src/main/java/io/reactivex/rxjava3/disposables/RunnableDisposable.java index 34203e86a99..390a7912b4a 100644 --- a/src/main/java/io/reactivex/rxjava3/disposables/RunnableDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/disposables/RunnableDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.disposables; import io.reactivex.rxjava3.annotations.NonNull; diff --git a/src/main/java/io/reactivex/rxjava3/disposables/SerialDisposable.java b/src/main/java/io/reactivex/rxjava3/disposables/SerialDisposable.java index 1f408f8c944..7b1f6463a86 100644 --- a/src/main/java/io/reactivex/rxjava3/disposables/SerialDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/disposables/SerialDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/disposables/SubscriptionDisposable.java b/src/main/java/io/reactivex/rxjava3/disposables/SubscriptionDisposable.java index f6756b58de2..48c5c7ab3d1 100644 --- a/src/main/java/io/reactivex/rxjava3/disposables/SubscriptionDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/disposables/SubscriptionDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.disposables; import org.reactivestreams.Subscription; diff --git a/src/main/java/io/reactivex/rxjava3/disposables/package-info.java b/src/main/java/io/reactivex/rxjava3/disposables/package-info.java index 29812d0ab76..00ff5dd6ffc 100644 --- a/src/main/java/io/reactivex/rxjava3/disposables/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/disposables/package-info.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ /** diff --git a/src/main/java/io/reactivex/rxjava3/exceptions/CompositeException.java b/src/main/java/io/reactivex/rxjava3/exceptions/CompositeException.java index d7a3457fe49..5d2928b28fe 100644 --- a/src/main/java/io/reactivex/rxjava3/exceptions/CompositeException.java +++ b/src/main/java/io/reactivex/rxjava3/exceptions/CompositeException.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.exceptions; import java.io.*; @@ -201,38 +199,41 @@ public void printStackTrace(PrintWriter s) { * Special handling for printing out a {@code CompositeException}. * Loops through all inner exceptions and prints them out. * - * @param s + * @param output * stream to print to */ - private void printStackTrace(PrintStreamOrWriter s) { - StringBuilder b = new StringBuilder(128); - b.append(this).append('\n'); + private void printStackTrace(PrintStreamOrWriter output) { + output.append(this).append("\n"); for (StackTraceElement myStackElement : getStackTrace()) { - b.append("\tat ").append(myStackElement).append('\n'); + output.append("\tat ").append(myStackElement).append("\n"); } int i = 1; for (Throwable ex : exceptions) { - b.append(" ComposedException ").append(i).append(" :\n"); - appendStackTrace(b, ex, "\t"); + output.append(" ComposedException ").append(i).append(" :\n"); + appendStackTrace(output, ex, "\t"); i++; } - s.println(b.toString()); + output.append("\n"); } - private void appendStackTrace(StringBuilder b, Throwable ex, String prefix) { - b.append(prefix).append(ex).append('\n'); + private void appendStackTrace(PrintStreamOrWriter output, Throwable ex, String prefix) { + output.append(prefix).append(ex).append('\n'); for (StackTraceElement stackElement : ex.getStackTrace()) { - b.append("\t\tat ").append(stackElement).append('\n'); + output.append("\t\tat ").append(stackElement).append('\n'); } if (ex.getCause() != null) { - b.append("\tCaused by: "); - appendStackTrace(b, ex.getCause(), ""); + output.append("\tCaused by: "); + appendStackTrace(output, ex.getCause(), ""); } } abstract static class PrintStreamOrWriter { - /** Prints the specified string as a line on this StreamOrWriter. */ - abstract void println(Object o); + /** + * Prints the object's string representation via the underlying PrintStream or PrintWriter. + * @param o the object to print + * @return this + */ + abstract PrintStreamOrWriter append(Object o); } /** @@ -246,11 +247,15 @@ static final class WrappedPrintStream extends PrintStreamOrWriter { } @Override - void println(Object o) { - printStream.println(o); + WrappedPrintStream append(Object o) { + printStream.print(o); + return this; } } + /** + * Same abstraction and implementation as in JDK to allow PrintStream and PrintWriter to share implementation. + */ static final class WrappedPrintWriter extends PrintStreamOrWriter { private final PrintWriter printWriter; @@ -259,8 +264,9 @@ static final class WrappedPrintWriter extends PrintStreamOrWriter { } @Override - void println(Object o) { - printWriter.println(o); + WrappedPrintWriter append(Object o) { + printWriter.print(o); + return this; } } diff --git a/src/main/java/io/reactivex/rxjava3/exceptions/Exceptions.java b/src/main/java/io/reactivex/rxjava3/exceptions/Exceptions.java index 41ddbd4fed9..155a2801d27 100644 --- a/src/main/java/io/reactivex/rxjava3/exceptions/Exceptions.java +++ b/src/main/java/io/reactivex/rxjava3/exceptions/Exceptions.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/exceptions/MissingBackpressureException.java b/src/main/java/io/reactivex/rxjava3/exceptions/MissingBackpressureException.java index f7b19a2fc2e..f0a173ba590 100644 --- a/src/main/java/io/reactivex/rxjava3/exceptions/MissingBackpressureException.java +++ b/src/main/java/io/reactivex/rxjava3/exceptions/MissingBackpressureException.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,6 +20,15 @@ public final class MissingBackpressureException extends RuntimeException { private static final long serialVersionUID = 8517344746016032542L; + /** + * The default error message. + *

+ * This can happen if the downstream doesn't call {@link org.reactivestreams.Subscription#request(long)} + * in time or at all. + * @since 3.1.6 + */ + public static final String DEFAULT_MESSAGE = "Could not emit value due to lack of requests"; + /** * Constructs a MissingBackpressureException without message or cause. */ @@ -35,4 +44,13 @@ public MissingBackpressureException(String message) { super(message); } + /** + * Constructs a new {@code MissingBackpressureException} with the + * default message {@value #DEFAULT_MESSAGE}. + * @return the new {@code MissingBackpressureException} instance. + * @since 3.1.6 + */ + public static MissingBackpressureException createDefault() { + return new MissingBackpressureException(DEFAULT_MESSAGE); + } } diff --git a/src/main/java/io/reactivex/rxjava3/exceptions/OnErrorNotImplementedException.java b/src/main/java/io/reactivex/rxjava3/exceptions/OnErrorNotImplementedException.java index d70769af39e..072b889a579 100644 --- a/src/main/java/io/reactivex/rxjava3/exceptions/OnErrorNotImplementedException.java +++ b/src/main/java/io/reactivex/rxjava3/exceptions/OnErrorNotImplementedException.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -50,4 +50,4 @@ public OnErrorNotImplementedException(String message, @NonNull Throwable e) { public OnErrorNotImplementedException(@NonNull Throwable e) { this("The exception was not handled due to missing onError handler in the subscribe() method call. Further reading: https://github.com/ReactiveX/RxJava/wiki/Error-Handling | " + e, e); } -} \ No newline at end of file +} diff --git a/src/main/java/io/reactivex/rxjava3/exceptions/ProtocolViolationException.java b/src/main/java/io/reactivex/rxjava3/exceptions/ProtocolViolationException.java index 9df2ed97625..66fab7f911d 100644 --- a/src/main/java/io/reactivex/rxjava3/exceptions/ProtocolViolationException.java +++ b/src/main/java/io/reactivex/rxjava3/exceptions/ProtocolViolationException.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/exceptions/QueueOverflowException.java b/src/main/java/io/reactivex/rxjava3/exceptions/QueueOverflowException.java new file mode 100644 index 00000000000..bdd8a25e6f1 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/exceptions/QueueOverflowException.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.exceptions; + +/** + * Indicates an overflow happened because the upstream disregarded backpressure completely or + * {@link org.reactivestreams.Subscriber#onNext(Object)} was called concurrently from multiple threads + * without synchronization. Rarely, it is an indication of bugs inside an operator. + * @since 3.1.6 + */ +public final class QueueOverflowException extends RuntimeException { + + private static final long serialVersionUID = 8517344746016032542L; + + /** + * The message for queue overflows. + *

+ * This can happen if the upstream disregards backpressure completely or calls + * {@link org.reactivestreams.Subscriber#onNext(Object)} concurrently from multiple threads + * without synchronization. Rarely, it is an indication of bugs inside an operator. + */ + private static final String DEFAULT_MESSAGE = "Queue overflow due to illegal concurrent onNext calls or a bug in an operator"; + + /** + * Constructs a QueueOverflowException with the default message. + */ + public QueueOverflowException() { + this(DEFAULT_MESSAGE); + } + + /** + * Constructs a QueueOverflowException with the given message but no cause. + * @param message the error message + */ + public QueueOverflowException(String message) { + super(message); + } +} diff --git a/src/main/java/io/reactivex/rxjava3/exceptions/UndeliverableException.java b/src/main/java/io/reactivex/rxjava3/exceptions/UndeliverableException.java index 08f926e9b3c..11a4c07f8a5 100644 --- a/src/main/java/io/reactivex/rxjava3/exceptions/UndeliverableException.java +++ b/src/main/java/io/reactivex/rxjava3/exceptions/UndeliverableException.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/exceptions/package-info.java b/src/main/java/io/reactivex/rxjava3/exceptions/package-info.java index 05ebb5bfb3a..91de82962f9 100644 --- a/src/main/java/io/reactivex/rxjava3/exceptions/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/exceptions/package-info.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ /** diff --git a/src/main/java/io/reactivex/rxjava3/flowables/ConnectableFlowable.java b/src/main/java/io/reactivex/rxjava3/flowables/ConnectableFlowable.java index 7f0cfd1100d..133d0186c8b 100644 --- a/src/main/java/io/reactivex/rxjava3/flowables/ConnectableFlowable.java +++ b/src/main/java/io/reactivex/rxjava3/flowables/ConnectableFlowable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,7 +16,7 @@ import java.util.Objects; import java.util.concurrent.TimeUnit; -import org.reactivestreams.Subscriber; +import org.reactivestreams.*; import io.reactivex.rxjava3.annotations.*; import io.reactivex.rxjava3.core.*; @@ -34,12 +34,12 @@ * can wait for all intended {@link Subscriber}s to {@link Flowable#subscribe} to the {@code Flowable} * before the {@code Flowable} begins emitting items. *

- * + * *

* When the upstream terminates, the {@code ConnectableFlowable} remains in this terminated state and, - * depending on the actual underlying implementation, relays cached events to late {@link Subscriber}s. + * depending on the actual underlying implementation, relays cached events to late {@code Subscriber}s. * In order to reuse and restart this {@code ConnectableFlowable}, the {@link #reset()} method has to be called. - * When called, this {@code ConnectableFlowable} will appear as fresh, unconnected source to new {@link Subscriber}s. + * When called, this {@code ConnectableFlowable} will appear as fresh, unconnected source to new {@code Subscriber}s. * Disposing the connection will reset the {@code ConnectableFlowable} to its fresh state and there is no need to call * {@code reset()} in this case. *

@@ -48,8 +48,7 @@ * there is no unwanted signal loss due to early {@code connect()} or {@code reset()} calls while {@code Subscriber}s are * still being subscribed to to this {@code ConnectableFlowable} to receive signals from the get go. *

- * @see RxJava Wiki: - * Connectable Observable Operators + * @see RxJava Wiki: Connectable Observable Operators * @param * the type of items emitted by the {@code ConnectableFlowable} * @since 2.0.0 @@ -67,13 +66,14 @@ public abstract class ConnectableFlowable extends Flowable { * @param connection * the action that receives the connection subscription before the subscription to source happens * allowing the caller to synchronously disconnect a synchronous source + * @throws NullPointerException if {@code connection} is {@code null} * @see ReactiveX documentation: Connect */ @SchedulerSupport(SchedulerSupport.NONE) public abstract void connect(@NonNull Consumer connection); /** - * Resets this ConnectableFlowable into its fresh state if it has terminated. + * Resets this {@code ConnectableFlowable} into its fresh state if it has terminated. *

* Calling this method on a fresh or active {@code ConnectableFlowable} has no effect. *

@@ -107,7 +107,7 @@ public final Disposable connect() { } /** - * Returns a {@code Flowable} that stays connected to this {@code ConnectableFlowable} as long as there + * Returns a {@link Flowable} that stays connected to this {@code ConnectableFlowable} as long as there * is at least one subscription to this {@code ConnectableFlowable}. *
*
Backpressure:
@@ -116,7 +116,7 @@ public final Disposable connect() { *
Scheduler:
*
This {@code refCount} overload does not operate on any particular {@link Scheduler}.
*
- * @return a {@link Flowable} + * @return the new {@code Flowable} instance * @see ReactiveX documentation: RefCount * @see #refCount(int) * @see #refCount(long, TimeUnit) @@ -142,7 +142,8 @@ public Flowable refCount() { *
*

History: 2.1.14 - experimental * @param subscriberCount the number of subscribers required to connect to the upstream - * @return the new Flowable instance + * @return the new {@link Flowable} instance + * @throws IllegalArgumentException if {@code subscriberCount} is non-positive * @since 2.2 */ @CheckReturnValue @@ -167,7 +168,8 @@ public final Flowable refCount(int subscriberCount) { *

History: 2.1.14 - experimental * @param timeout the time to wait before disconnecting after all subscribers unsubscribed * @param unit the time unit of the timeout - * @return the new Flowable instance + * @return the new {@link Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see #refCount(long, TimeUnit, Scheduler) * @since 2.2 */ @@ -194,7 +196,8 @@ public final Flowable refCount(long timeout, @NonNull TimeUnit unit) { * @param timeout the time to wait before disconnecting after all subscribers unsubscribed * @param unit the time unit of the timeout * @param scheduler the target scheduler to wait on before disconnecting - * @return the new Flowable instance + * @return the new {@link Flowable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -220,7 +223,9 @@ public final Flowable refCount(long timeout, @NonNull TimeUnit unit, @NonNull * @param subscriberCount the number of subscribers required to connect to the upstream * @param timeout the time to wait before disconnecting after all subscribers unsubscribed * @param unit the time unit of the timeout - * @return the new Flowable instance + * @return the new {@link Flowable} instance + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code subscriberCount} is non-positive * @see #refCount(int, long, TimeUnit, Scheduler) * @since 2.2 */ @@ -248,7 +253,7 @@ public final Flowable refCount(int subscriberCount, long timeout, @NonNull Ti * @param timeout the time to wait before disconnecting after all subscribers unsubscribed * @param unit the time unit of the timeout * @param scheduler the target scheduler to wait on before disconnecting - * @return the new Flowable instance + * @return the new {@link Flowable} instance * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @throws IllegalArgumentException if {@code subscriberCount} is non-positive * @since 2.2 @@ -265,20 +270,20 @@ public final Flowable refCount(int subscriberCount, long timeout, @NonNull Ti } /** - * Returns a Flowable that automatically connects (at most once) to this ConnectableFlowable - * when the first Subscriber subscribes. + * Returns a {@link Flowable} that automatically connects (at most once) to this {@code ConnectableFlowable} + * when the first {@link Subscriber} subscribes. *

* *

* The connection happens after the first subscription and happens at most once - * during the lifetime of the returned Flowable. If this ConnectableFlowable - * terminates, the connection is never renewed, no matter how Subscribers come + * during the lifetime of the returned {@code Flowable}. If this {@code ConnectableFlowable} + * terminates, the connection is never renewed, no matter how {@code Subscriber}s come * and go. Use {@link #refCount()} to renew a connection or dispose an active - * connection when all {@code Subscriber}s have cancelled their {@code Subscription}s. + * connection when all {@code Subscriber}s have cancelled their {@link Subscription}s. *

* This overload does not allow disconnecting the connection established via * {@link #connect(Consumer)}. Use the {@link #autoConnect(int, Consumer)} overload - * to gain access to the {@code Disposable} representing the only connection. + * to gain access to the {@link Disposable} representing the only connection. *

*
Backpressure:
*
The operator itself doesn't interfere with backpressure which is determined by @@ -287,8 +292,8 @@ public final Flowable refCount(int subscriberCount, long timeout, @NonNull Ti *
{@code autoConnect} does not operate by default on a particular {@link Scheduler}.
*
* - * @return a Flowable that automatically connects to this ConnectableFlowable - * when the first Subscriber subscribes + * @return a new {@code Flowable} instance that automatically connects to this {@code ConnectableFlowable} + * when the first {@code Subscriber} subscribes * @see #refCount() * @see #autoConnect(int, Consumer) */ @@ -300,20 +305,20 @@ public Flowable autoConnect() { return autoConnect(1); } /** - * Returns a Flowable that automatically connects (at most once) to this ConnectableFlowable - * when the specified number of Subscribers subscribe to it. + * Returns a {@link Flowable} that automatically connects (at most once) to this {@code ConnectableFlowable} + * when the specified number of {@link Subscriber}s subscribe to it. *

* *

* The connection happens after the given number of subscriptions and happens at most once - * during the lifetime of the returned Flowable. If this ConnectableFlowable - * terminates, the connection is never renewed, no matter how Subscribers come + * during the lifetime of the returned {@code Flowable}. If this {@code ConnectableFlowable} + * terminates, the connection is never renewed, no matter how {@code Subscriber}s come * and go. Use {@link #refCount()} to renew a connection or dispose an active - * connection when all {@code Subscriber}s have cancelled their {@code Subscription}s. + * connection when all {@code Subscriber}s have cancelled their {@link Subscription}s. *

* This overload does not allow disconnecting the connection established via * {@link #connect(Consumer)}. Use the {@link #autoConnect(int, Consumer)} overload - * to gain access to the {@code Disposable} representing the only connection. + * to gain access to the {@link Disposable} representing the only connection. *

*
Backpressure:
*
The operator itself doesn't interfere with backpressure which is determined by @@ -323,10 +328,10 @@ public Flowable autoConnect() { *
* * @param numberOfSubscribers the number of subscribers to await before calling connect - * on the ConnectableFlowable. A non-positive value indicates + * on the {@code ConnectableFlowable}. A non-positive value indicates * an immediate connection. - * @return a Flowable that automatically connects to this ConnectableFlowable - * when the specified number of Subscribers subscribe to it + * @return a new {@code Flowable} instance that automatically connects to this {@code ConnectableFlowable} + * when the specified number of {@code Subscriber}s subscribe to it */ @NonNull @CheckReturnValue @@ -337,17 +342,17 @@ public Flowable autoConnect(int numberOfSubscribers) { } /** - * Returns a Flowable that automatically connects (at most once) to this ConnectableFlowable - * when the specified number of Subscribers subscribe to it and calls the - * specified callback with the Subscription associated with the established connection. + * Returns a {@link Flowable} that automatically connects (at most once) to this {@code ConnectableFlowable} + * when the specified number of {@link Subscriber}s subscribe to it and calls the + * specified callback with the {@link Disposable} associated with the established connection. *

* *

* The connection happens after the given number of subscriptions and happens at most once - * during the lifetime of the returned Flowable. If this ConnectableFlowable - * terminates, the connection is never renewed, no matter how Subscribers come + * during the lifetime of the returned {@code Flowable}. If this {@code ConnectableFlowable} + * terminates, the connection is never renewed, no matter how {@code Subscriber}s come * and go. Use {@link #refCount()} to renew a connection or dispose an active - * connection when all {@code Subscriber}s have cancelled their {@code Subscription}s. + * connection when all {@code Subscriber}s have cancelled their {@link Subscription}s. *

*
Backpressure:
*
The operator itself doesn't interfere with backpressure which is determined by @@ -357,19 +362,21 @@ public Flowable autoConnect(int numberOfSubscribers) { *
* * @param numberOfSubscribers the number of subscribers to await before calling connect - * on the ConnectableFlowable. A non-positive value indicates + * on the {@code ConnectableFlowable}. A non-positive value indicates * an immediate connection. - * @param connection the callback Consumer that will receive the Subscription representing the + * @param connection the callback {@link Consumer} that will receive the {@code Disposable} representing the * established connection - * @return a Flowable that automatically connects to this ConnectableFlowable - * when the specified number of Subscribers subscribe to it and calls the - * specified callback with the Subscription associated with the established connection + * @return a new {@code Flowable} instance that automatically connects to this {@code ConnectableFlowable} + * when the specified number of {@code Subscriber}s subscribe to it and calls the + * specified callback with the {@code Disposable} associated with the established connection + * @throws NullPointerException if {@code connection} is {@code null} */ @NonNull @CheckReturnValue @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) public Flowable autoConnect(int numberOfSubscribers, @NonNull Consumer connection) { + Objects.requireNonNull(connection, "connection is null"); if (numberOfSubscribers <= 0) { this.connect(connection); return RxJavaPlugins.onAssembly(this); diff --git a/src/main/java/io/reactivex/rxjava3/flowables/GroupedFlowable.java b/src/main/java/io/reactivex/rxjava3/flowables/GroupedFlowable.java index d9564c3e6e0..609fc7808fe 100644 --- a/src/main/java/io/reactivex/rxjava3/flowables/GroupedFlowable.java +++ b/src/main/java/io/reactivex/rxjava3/flowables/GroupedFlowable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.flowables; import io.reactivex.rxjava3.annotations.Nullable; diff --git a/src/main/java/io/reactivex/rxjava3/flowables/package-info.java b/src/main/java/io/reactivex/rxjava3/flowables/package-info.java index 75a6dec4e96..06475a34ea9 100644 --- a/src/main/java/io/reactivex/rxjava3/flowables/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/flowables/package-info.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ /** diff --git a/src/main/java/io/reactivex/rxjava3/functions/Action.java b/src/main/java/io/reactivex/rxjava3/functions/Action.java index da0e76e0a62..509e5fcb64b 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/Action.java +++ b/src/main/java/io/reactivex/rxjava3/functions/Action.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/functions/BiConsumer.java b/src/main/java/io/reactivex/rxjava3/functions/BiConsumer.java index 7fa60ef4c73..09fec68cbf3 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/BiConsumer.java +++ b/src/main/java/io/reactivex/rxjava3/functions/BiConsumer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,13 +13,15 @@ package io.reactivex.rxjava3.functions; +import io.reactivex.rxjava3.annotations.NonNull; + /** * A functional interface (callback) that accepts two values (of possibly different types). * @param the first value type * @param the second value type */ @FunctionalInterface -public interface BiConsumer { +public interface BiConsumer<@NonNull T1, @NonNull T2> { /** * Performs an operation on the given values. diff --git a/src/main/java/io/reactivex/rxjava3/functions/BiFunction.java b/src/main/java/io/reactivex/rxjava3/functions/BiFunction.java index 174cc3c6d98..27aa9ee016c 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/BiFunction.java +++ b/src/main/java/io/reactivex/rxjava3/functions/BiFunction.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ * @param the result type */ @FunctionalInterface -public interface BiFunction { +public interface BiFunction<@NonNull T1, @NonNull T2, @NonNull R> { /** * Calculate a value based on the input values. @@ -31,6 +31,5 @@ public interface BiFunction { * @return the result value * @throws Throwable if the implementation wishes to throw any type of exception */ - @NonNull - R apply(@NonNull T1 t1, @NonNull T2 t2) throws Throwable; + R apply(T1 t1, T2 t2) throws Throwable; } diff --git a/src/main/java/io/reactivex/rxjava3/functions/BiPredicate.java b/src/main/java/io/reactivex/rxjava3/functions/BiPredicate.java index fc41682ef5b..e45397aab78 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/BiPredicate.java +++ b/src/main/java/io/reactivex/rxjava3/functions/BiPredicate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,7 +21,7 @@ * @param the second value */ @FunctionalInterface -public interface BiPredicate { +public interface BiPredicate<@NonNull T1, @NonNull T2> { /** * Test the given input values and return a boolean. diff --git a/src/main/java/io/reactivex/rxjava3/functions/BooleanSupplier.java b/src/main/java/io/reactivex/rxjava3/functions/BooleanSupplier.java index b30087fbd7b..4e3b447b6e1 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/BooleanSupplier.java +++ b/src/main/java/io/reactivex/rxjava3/functions/BooleanSupplier.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/functions/Cancellable.java b/src/main/java/io/reactivex/rxjava3/functions/Cancellable.java index b9f3420c1b5..574c8322681 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/Cancellable.java +++ b/src/main/java/io/reactivex/rxjava3/functions/Cancellable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/functions/Consumer.java b/src/main/java/io/reactivex/rxjava3/functions/Consumer.java index 788622c170d..3ac1806438d 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/Consumer.java +++ b/src/main/java/io/reactivex/rxjava3/functions/Consumer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,12 +13,14 @@ package io.reactivex.rxjava3.functions; +import io.reactivex.rxjava3.annotations.NonNull; + /** * A functional interface (callback) that accepts a single value. * @param the value type */ @FunctionalInterface -public interface Consumer { +public interface Consumer<@NonNull T> { /** * Consume the given value. * @param t the value diff --git a/src/main/java/io/reactivex/rxjava3/functions/Function.java b/src/main/java/io/reactivex/rxjava3/functions/Function.java index d81a2dec520..40e11ca3bae 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/Function.java +++ b/src/main/java/io/reactivex/rxjava3/functions/Function.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,12 +23,12 @@ * @param the output value type */ @FunctionalInterface -public interface Function { +public interface Function<@NonNull T, @NonNull R> { /** * Apply some calculation to the input value and return some other value. * @param t the input value * @return the output value * @throws Throwable if the implementation wishes to throw any type of exception */ - R apply(@NonNull T t) throws Throwable; + R apply(T t) throws Throwable; } diff --git a/src/main/java/io/reactivex/rxjava3/functions/Function3.java b/src/main/java/io/reactivex/rxjava3/functions/Function3.java index cdc65112e7a..377cceaeafd 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/Function3.java +++ b/src/main/java/io/reactivex/rxjava3/functions/Function3.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,7 +23,7 @@ * @param the result type */ @FunctionalInterface -public interface Function3 { +public interface Function3<@NonNull T1, @NonNull T2, @NonNull T3, @NonNull R> { /** * Calculate a value based on the input values. * @param t1 the first value @@ -32,6 +32,5 @@ public interface Function3 { * @return the result value * @throws Throwable if the implementation wishes to throw any type of exception */ - @NonNull - R apply(@NonNull T1 t1, @NonNull T2 t2, @NonNull T3 t3) throws Throwable; + R apply(T1 t1, T2 t2, T3 t3) throws Throwable; } diff --git a/src/main/java/io/reactivex/rxjava3/functions/Function4.java b/src/main/java/io/reactivex/rxjava3/functions/Function4.java index 84c3ab1449c..36db3858191 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/Function4.java +++ b/src/main/java/io/reactivex/rxjava3/functions/Function4.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,7 +24,7 @@ * @param the result type */ @FunctionalInterface -public interface Function4 { +public interface Function4<@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull R> { /** * Calculate a value based on the input values. * @param t1 the first value @@ -34,6 +34,5 @@ public interface Function4 { * @return the result value * @throws Throwable if the implementation wishes to throw any type of exception */ - @NonNull - R apply(@NonNull T1 t1, @NonNull T2 t2, @NonNull T3 t3, @NonNull T4 t4) throws Throwable; + R apply(T1 t1, T2 t2, T3 t3, T4 t4) throws Throwable; } diff --git a/src/main/java/io/reactivex/rxjava3/functions/Function5.java b/src/main/java/io/reactivex/rxjava3/functions/Function5.java index 77f2ff7220b..d3fc1504c41 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/Function5.java +++ b/src/main/java/io/reactivex/rxjava3/functions/Function5.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ * @param the result type */ @FunctionalInterface -public interface Function5 { +public interface Function5<@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull R> { /** * Calculate a value based on the input values. * @param t1 the first value @@ -36,6 +36,5 @@ public interface Function5 { * @return the result value * @throws Throwable if the implementation wishes to throw any type of exception */ - @NonNull - R apply(@NonNull T1 t1, @NonNull T2 t2, @NonNull T3 t3, @NonNull T4 t4, @NonNull T5 t5) throws Throwable; + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) throws Throwable; } diff --git a/src/main/java/io/reactivex/rxjava3/functions/Function6.java b/src/main/java/io/reactivex/rxjava3/functions/Function6.java index 50c25f3df96..2969a39f823 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/Function6.java +++ b/src/main/java/io/reactivex/rxjava3/functions/Function6.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,7 @@ * @param the result type */ @FunctionalInterface -public interface Function6 { +public interface Function6<@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull R> { /** * Calculate a value based on the input values. * @param t1 the first value @@ -38,6 +38,5 @@ public interface Function6 { * @return the result value * @throws Throwable if the implementation wishes to throw any type of exception */ - @NonNull - R apply(@NonNull T1 t1, @NonNull T2 t2, @NonNull T3 t3, @NonNull T4 t4, @NonNull T5 t5, @NonNull T6 t6) throws Throwable; + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) throws Throwable; } diff --git a/src/main/java/io/reactivex/rxjava3/functions/Function7.java b/src/main/java/io/reactivex/rxjava3/functions/Function7.java index 613800a4c1a..091b2032964 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/Function7.java +++ b/src/main/java/io/reactivex/rxjava3/functions/Function7.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,7 +27,7 @@ * @param the result type */ @FunctionalInterface -public interface Function7 { +public interface Function7<@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull R> { /** * Calculate a value based on the input values. * @param t1 the first value @@ -40,6 +40,5 @@ public interface Function7 { * @return the result value * @throws Throwable if the implementation wishes to throw any type of exception */ - @NonNull - R apply(@NonNull T1 t1, @NonNull T2 t2, @NonNull T3 t3, @NonNull T4 t4, @NonNull T5 t5, @NonNull T6 t6, @NonNull T7 t7) throws Throwable; + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) throws Throwable; } diff --git a/src/main/java/io/reactivex/rxjava3/functions/Function8.java b/src/main/java/io/reactivex/rxjava3/functions/Function8.java index 2fda54ea407..c8e21acf9d4 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/Function8.java +++ b/src/main/java/io/reactivex/rxjava3/functions/Function8.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -28,7 +28,7 @@ * @param the result type */ @FunctionalInterface -public interface Function8 { +public interface Function8<@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull R> { /** * Calculate a value based on the input values. * @param t1 the first value @@ -42,6 +42,5 @@ public interface Function8 { * @return the result value * @throws Throwable if the implementation wishes to throw any type of exception */ - @NonNull - R apply(@NonNull T1 t1, @NonNull T2 t2, @NonNull T3 t3, @NonNull T4 t4, @NonNull T5 t5, @NonNull T6 t6, @NonNull T7 t7, @NonNull T8 t8) throws Throwable; + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) throws Throwable; } diff --git a/src/main/java/io/reactivex/rxjava3/functions/Function9.java b/src/main/java/io/reactivex/rxjava3/functions/Function9.java index 3eb0779e30f..0b182eb5f3c 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/Function9.java +++ b/src/main/java/io/reactivex/rxjava3/functions/Function9.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -29,7 +29,7 @@ * @param the result type */ @FunctionalInterface -public interface Function9 { +public interface Function9<@NonNull T1, @NonNull T2, @NonNull T3, @NonNull T4, @NonNull T5, @NonNull T6, @NonNull T7, @NonNull T8, @NonNull T9, @NonNull R> { /** * Calculate a value based on the input values. * @param t1 the first value @@ -44,6 +44,5 @@ public interface Function9 { * @return the result value * @throws Throwable if the implementation wishes to throw any type of exception */ - @NonNull - R apply(@NonNull T1 t1, @NonNull T2 t2, @NonNull T3 t3, @NonNull T4 t4, @NonNull T5 t5, @NonNull T6 t6, @NonNull T7 t7, @NonNull T8 t8, @NonNull T9 t9) throws Throwable; + R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) throws Throwable; } diff --git a/src/main/java/io/reactivex/rxjava3/functions/IntFunction.java b/src/main/java/io/reactivex/rxjava3/functions/IntFunction.java index e01cc13ab53..3a405aac263 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/IntFunction.java +++ b/src/main/java/io/reactivex/rxjava3/functions/IntFunction.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.functions; import io.reactivex.rxjava3.annotations.NonNull; @@ -19,13 +20,12 @@ * @param the returned value type */ @FunctionalInterface -public interface IntFunction { +public interface IntFunction<@NonNull T> { /** * Calculates a value based on a primitive integer input. * @param i the input value * @return the result Object * @throws Throwable if the implementation wishes to throw any type of exception */ - @NonNull T apply(int i) throws Throwable; } diff --git a/src/main/java/io/reactivex/rxjava3/functions/LongConsumer.java b/src/main/java/io/reactivex/rxjava3/functions/LongConsumer.java index 9af7de4f477..5b12752c1d0 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/LongConsumer.java +++ b/src/main/java/io/reactivex/rxjava3/functions/LongConsumer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.functions; /** diff --git a/src/main/java/io/reactivex/rxjava3/functions/Predicate.java b/src/main/java/io/reactivex/rxjava3/functions/Predicate.java index 99450f865b7..1bce2d6bffe 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/Predicate.java +++ b/src/main/java/io/reactivex/rxjava3/functions/Predicate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,12 +20,12 @@ * @param the first value */ @FunctionalInterface -public interface Predicate { +public interface Predicate<@NonNull T> { /** * Test the given input value and return a boolean. * @param t the value * @return the boolean result * @throws Throwable if the implementation wishes to throw any type of exception */ - boolean test(@NonNull T t) throws Throwable; + boolean test(T t) throws Throwable; } diff --git a/src/main/java/io/reactivex/rxjava3/functions/Supplier.java b/src/main/java/io/reactivex/rxjava3/functions/Supplier.java index af5052ab835..ebf7fdda6d9 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/Supplier.java +++ b/src/main/java/io/reactivex/rxjava3/functions/Supplier.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/functions/package-info.java b/src/main/java/io/reactivex/rxjava3/functions/package-info.java index a7d92ce8fb8..ab9dad0426f 100644 --- a/src/main/java/io/reactivex/rxjava3/functions/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/functions/package-info.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ /** diff --git a/src/main/java/io/reactivex/rxjava3/internal/disposables/ArrayCompositeDisposable.java b/src/main/java/io/reactivex/rxjava3/internal/disposables/ArrayCompositeDisposable.java index 5ebcdde15b6..c9a6bc9bc49 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/disposables/ArrayCompositeDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/disposables/ArrayCompositeDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/disposables/CancellableDisposable.java b/src/main/java/io/reactivex/rxjava3/internal/disposables/CancellableDisposable.java index 314464e156e..863f52e91bc 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/disposables/CancellableDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/disposables/CancellableDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/disposables/DisposableHelper.java b/src/main/java/io/reactivex/rxjava3/internal/disposables/DisposableHelper.java index 1f2d2122d1b..79dbd855aca 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/disposables/DisposableHelper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/disposables/DisposableHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/disposables/EmptyDisposable.java b/src/main/java/io/reactivex/rxjava3/internal/disposables/EmptyDisposable.java index 51acc86c752..fdb30932ed5 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/disposables/EmptyDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/disposables/EmptyDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,7 +15,7 @@ import io.reactivex.rxjava3.annotations.Nullable; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.internal.fuseable.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueDisposable; /** * Represents a stateless empty Disposable that reports being always diff --git a/src/main/java/io/reactivex/rxjava3/internal/disposables/ListCompositeDisposable.java b/src/main/java/io/reactivex/rxjava3/internal/disposables/ListCompositeDisposable.java index 8a6d4dd9923..4c4b1f8a73e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/disposables/ListCompositeDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/disposables/ListCompositeDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.disposables; import java.util.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/disposables/SequentialDisposable.java b/src/main/java/io/reactivex/rxjava3/internal/disposables/SequentialDisposable.java index d9922ebec80..f6aef6bdd3f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/disposables/SequentialDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/disposables/SequentialDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/functions/Functions.java b/src/main/java/io/reactivex/rxjava3/internal/functions/Functions.java index 1fee43d07e5..e0d3dead3c5 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/functions/Functions.java +++ b/src/main/java/io/reactivex/rxjava3/internal/functions/Functions.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.functions; import java.util.*; @@ -124,8 +125,6 @@ public static Consumer emptyConsumer() { static final Supplier NULL_SUPPLIER = new NullProvider(); - static final Comparator NATURAL_COMPARATOR = new NaturalObjectComparator(); - @SuppressWarnings("unchecked") @NonNull public static Predicate alwaysTrue() { @@ -144,17 +143,6 @@ public static Supplier nullSupplier() { return (Supplier)NULL_SUPPLIER; } - /** - * Returns a natural order comparator which casts the parameters to Comparable. - * @param the value type - * @return a natural order comparator which casts the parameters to Comparable - */ - @SuppressWarnings("unchecked") - @NonNull - public static Comparator naturalOrder() { - return (Comparator)NATURAL_COMPARATOR; - } - static final class FutureAction implements Action { final Future future; @@ -294,13 +282,8 @@ public static Predicate equalsWith(T value) { return new EqualsPredicate<>(value); } - enum HashSetCallable implements Supplier>, Callable> { + enum HashSetSupplier implements Supplier> { INSTANCE; - @Override - public Set call() { - return new HashSet<>(); - } - @Override public Set get() { return new HashSet<>(); @@ -309,7 +292,7 @@ public Set get() { @SuppressWarnings({ "rawtypes", "unchecked" }) public static Supplier> createHashSet() { - return (Supplier)HashSetCallable.INSTANCE; + return (Supplier)HashSetSupplier.INSTANCE; } static final class NotificationOnNext implements Consumer { @@ -755,26 +738,13 @@ public boolean test(Object o) { } } - static final class NullProvider implements Callable, Supplier { - @Override - public Object call() { - return null; - } - + static final class NullProvider implements Supplier { @Override public Object get() { return null; } } - static final class NaturalObjectComparator implements Comparator { - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public int compare(Object a, Object b) { - return ((Comparable)a).compareTo(b); - } - } - static final class MaxRequestSubscription implements Consumer { @Override public void accept(Subscription t) { diff --git a/src/main/java/io/reactivex/rxjava3/internal/functions/ObjectHelper.java b/src/main/java/io/reactivex/rxjava3/internal/functions/ObjectHelper.java index 05bceafa1d2..5bbdf22ad3f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/functions/ObjectHelper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/functions/ObjectHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.functions; import io.reactivex.rxjava3.functions.BiPredicate; diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/AbstractEmptyQueueFuseable.java b/src/main/java/io/reactivex/rxjava3/internal/fuseable/AbstractEmptyQueueFuseable.java new file mode 100644 index 00000000000..13732bd426d --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/fuseable/AbstractEmptyQueueFuseable.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.fuseable; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; + +/** + * Represents an empty, async-only {@link QueueFuseable} instance. + * + * @param the output value type + * @since 3.0.0 + */ +public abstract class AbstractEmptyQueueFuseable +implements QueueSubscription, QueueDisposable { + + @Override + public final int requestFusion(int mode) { + return mode & ASYNC; + } + + @Override + public final boolean offer(@NonNull T value) { + throw new UnsupportedOperationException("Should not be called!"); + } + + @Override + public final boolean offer(@NonNull T v1, @NonNull T v2) { + throw new UnsupportedOperationException("Should not be called!"); + } + + @Override + public final T poll() throws Throwable { + return null; // always empty + } + + @Override + public final boolean isEmpty() { + return true; // always empty + } + + @Override + public final void clear() { + // always empty + } + + @Override + public final void request(long n) { + // no items to request + } + + @Override + public void cancel() { + // default No-op + } + + @Override + public void dispose() { + // default No-op + } + + @Override + public boolean isDisposed() { + return false; + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/CancellableQueueFuseable.java b/src/main/java/io/reactivex/rxjava3/internal/fuseable/CancellableQueueFuseable.java new file mode 100644 index 00000000000..71f993e2267 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/fuseable/CancellableQueueFuseable.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.fuseable; + +import io.reactivex.rxjava3.operators.QueueFuseable; + +/** + * Represents an empty, async-only {@link QueueFuseable} instance that tracks and exposes a + * canceled/disposed state. + * + * @param the output value type + * @since 3.0.0 + */ +public final class CancellableQueueFuseable +extends AbstractEmptyQueueFuseable { + + volatile boolean disposed; + + @Override + public void cancel() { + disposed = true; + } + + @Override + public void dispose() { + disposed = true; + } + + @Override + public boolean isDisposed() { + return disposed; + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/FuseToFlowable.java b/src/main/java/io/reactivex/rxjava3/internal/fuseable/FuseToFlowable.java index 2b7bb614e7f..fe70b40a011 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/FuseToFlowable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/fuseable/FuseToFlowable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,6 +13,7 @@ package io.reactivex.rxjava3.internal.fuseable; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.Flowable; /** @@ -20,8 +21,10 @@ * the operator goes from Flowable to some other reactive type and then the sequence calls * for toFlowable again: *
- * Single<Integer> single = Flowable.range(1, 10).reduce((a, b) -> a + b);
- * Flowable<Integer> flowable = single.toFlowable();
+ * {@code
+ * Single single = Flowable.range(1, 10).reduce((a, b) -> a + b);
+ * Flowable flowable = single.toFlowable();
+ * }
  * 
* * The {@code Single.toFlowable()} will check for this interface and call the {@link #fuseToFlowable()} @@ -32,12 +35,13 @@ * * @param the value type */ -public interface FuseToFlowable { +public interface FuseToFlowable<@NonNull T> { /** * Returns a (direct) Flowable for the operator. *

The implementation should handle the necessary RxJavaPlugins wrapping. * @return the Flowable instance */ + @NonNull Flowable fuseToFlowable(); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/FuseToMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/fuseable/FuseToMaybe.java index c2db8c7de6b..13ccd6be751 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/FuseToMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/fuseable/FuseToMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,6 +13,7 @@ package io.reactivex.rxjava3.internal.fuseable; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.Maybe; /** @@ -20,8 +21,10 @@ * the operator goes from Maybe to some other reactive type and then the sequence calls * for toMaybe again: *

- * Single<Integer> single = Maybe.just(1).isEmpty();
- * Maybe<Integer> maybe = single.toMaybe();
+ * {@code
+ * Single single = Maybe.just(1).isEmpty();
+ * Maybe maybe = single.toMaybe();
+ * }
  * 
* * The {@code Single.toMaybe()} will check for this interface and call the {@link #fuseToMaybe()} @@ -32,12 +35,13 @@ * * @param the value type */ -public interface FuseToMaybe { +public interface FuseToMaybe<@NonNull T> { /** * Returns a (direct) Maybe for the operator. *

The implementation should handle the necessary RxJavaPlugins wrapping. * @return the Maybe instance */ + @NonNull Maybe fuseToMaybe(); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/FuseToObservable.java b/src/main/java/io/reactivex/rxjava3/internal/fuseable/FuseToObservable.java index 8488ccf6e8b..d7ae761e379 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/FuseToObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/fuseable/FuseToObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,6 +13,7 @@ package io.reactivex.rxjava3.internal.fuseable; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.Observable; /** @@ -20,8 +21,10 @@ * the operator goes from Observable to some other reactive type and then the sequence calls * for toObservable again: *

- * Single<Integer> single = Observable.range(1, 10).reduce((a, b) -> a + b);
- * Observable<Integer> observable = single.toObservable();
+ * {@code
+ * Single single = Observable.range(1, 10).reduce((a, b) -> a + b);
+ * Observable observable = single.toObservable();
+ * }
  * 
* * The {@code Single.toObservable()} will check for this interface and call the {@link #fuseToObservable()} @@ -32,12 +35,13 @@ * * @param the value type */ -public interface FuseToObservable { +public interface FuseToObservable<@NonNull T> { /** * Returns a (direct) Observable for the operator. *

The implementation should handle the necessary RxJavaPlugins wrapping. * @return the Observable instance */ + @NonNull Observable fuseToObservable(); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamCompletableSource.java b/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamCompletableSource.java index 38f199b9dc8..fddb14ef0b7 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamCompletableSource.java +++ b/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamCompletableSource.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,6 +13,7 @@ package io.reactivex.rxjava3.internal.fuseable; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.CompletableSource; /** @@ -25,5 +26,6 @@ public interface HasUpstreamCompletableSource { *

Allows discovering the chain of observables. * @return the source CompletableSource */ + @NonNull CompletableSource source(); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamMaybeSource.java b/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamMaybeSource.java index 0a7d36ed863..121e2937e44 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamMaybeSource.java +++ b/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamMaybeSource.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,6 +13,7 @@ package io.reactivex.rxjava3.internal.fuseable; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.MaybeSource; /** @@ -21,11 +22,12 @@ * * @param the value type */ -public interface HasUpstreamMaybeSource { +public interface HasUpstreamMaybeSource<@NonNull T> { /** * Returns the upstream source of this Maybe. *

Allows discovering the chain of observables. * @return the source MaybeSource */ + @NonNull MaybeSource source(); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamObservableSource.java b/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamObservableSource.java index 0ab946c4c0d..1a1e878b650 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamObservableSource.java +++ b/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamObservableSource.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,6 +13,7 @@ package io.reactivex.rxjava3.internal.fuseable; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.ObservableSource; /** @@ -21,11 +22,12 @@ * * @param the value type */ -public interface HasUpstreamObservableSource { +public interface HasUpstreamObservableSource<@NonNull T> { /** * Returns the upstream source of this Observable. *

Allows discovering the chain of observables. * @return the source ObservableSource */ + @NonNull ObservableSource source(); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamPublisher.java index 9afa5ce9e04..5a46f38555e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,13 +15,15 @@ import org.reactivestreams.Publisher; +import io.reactivex.rxjava3.annotations.NonNull; + /** * Interface indicating the implementor has an upstream Publisher-like source available * via {@link #source()} method. * * @param the value type */ -public interface HasUpstreamPublisher { +public interface HasUpstreamPublisher<@NonNull T> { /** * Returns the source Publisher. *

@@ -29,5 +31,6 @@ public interface HasUpstreamPublisher { * graph of sequences. * @return the source Publisher */ + @NonNull Publisher source(); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamSingleSource.java b/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamSingleSource.java index db94a572e1e..ef833ae2ff6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamSingleSource.java +++ b/src/main/java/io/reactivex/rxjava3/internal/fuseable/HasUpstreamSingleSource.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,6 +13,7 @@ package io.reactivex.rxjava3.internal.fuseable; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.SingleSource; /** @@ -21,11 +22,12 @@ * * @param the value type */ -public interface HasUpstreamSingleSource { +public interface HasUpstreamSingleSource<@NonNull T> { /** * Returns the upstream source of this Single. *

Allows discovering the chain of observables. * @return the source SingleSource */ + @NonNull SingleSource source(); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/package-info.java b/src/main/java/io/reactivex/rxjava3/internal/fuseable/package-info.java index b4ee8690766..339eabbfd27 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/internal/fuseable/package-info.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/CompletableFromCompletionStage.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/CompletableFromCompletionStage.java index 44f539bf4bf..639516d005a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/CompletableFromCompletionStage.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/CompletableFromCompletionStage.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.concurrent.CompletionStage; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/CompletionStageConsumer.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/CompletionStageConsumer.java index d92e56041e1..24102907343 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/CompletionStageConsumer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/CompletionStageConsumer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.NoSuchElementException; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableCollectWithCollector.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableCollectWithCollector.java index bc408db3046..63ca949295b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableCollectWithCollector.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableCollectWithCollector.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.Objects; @@ -36,9 +37,9 @@ public final class FlowableCollectWithCollector extends Flowable { final Flowable source; - final Collector collector; + final Collector collector; - public FlowableCollectWithCollector(Flowable source, Collector collector) { + public FlowableCollectWithCollector(Flowable source, Collector collector) { this.source = source; this.collector = collector; } @@ -46,7 +47,7 @@ public FlowableCollectWithCollector(Flowable source, Collector colle @Override protected void subscribeActual(@NonNull Subscriber s) { A container; - BiConsumer accumulator; + BiConsumer accumulator; Function finisher; try { diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableCollectWithCollectorSingle.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableCollectWithCollectorSingle.java index 134de68415e..aba390e1da0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableCollectWithCollectorSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableCollectWithCollectorSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.Objects; @@ -39,9 +40,9 @@ public final class FlowableCollectWithCollectorSingle extends Single final Flowable source; - final Collector collector; + final Collector collector; - public FlowableCollectWithCollectorSingle(Flowable source, Collector collector) { + public FlowableCollectWithCollectorSingle(Flowable source, Collector collector) { this.source = source; this.collector = collector; } @@ -54,7 +55,7 @@ public Flowable fuseToFlowable() { @Override protected void subscribeActual(@NonNull SingleObserver observer) { A container; - BiConsumer accumulator; + BiConsumer accumulator; Function finisher; try { diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFirstStageSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFirstStageSubscriber.java index 5af6cc5aaca..19bfcbff6dc 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFirstStageSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFirstStageSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.NoSuchElementException; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFlatMapStream.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFlatMapStream.java index b01b24748a8..48ea8b6e5f0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFlatMapStream.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFlatMapStream.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,10 +23,12 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** @@ -172,7 +174,7 @@ public void onNext(T t) { if (sourceMode != QueueFuseable.ASYNC) { if (!queue.offer(t)) { upstream.cancel(); - onError(new MissingBackpressureException("Queue full?!")); + onError(new QueueOverflowException()); return; } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromCompletionStage.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromCompletionStage.java index f864cdd96d6..1ee0f7786ed 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromCompletionStage.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromCompletionStage.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.concurrent.CompletionStage; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromStream.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromStream.java index 55ec854ddfd..4fd3b4eb007 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromStream.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromStream.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.Iterator; @@ -22,9 +23,10 @@ import io.reactivex.rxjava3.annotations.*; import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.exceptions.Exceptions; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableLastStageSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableLastStageSubscriber.java index c9a93eeb0ea..0bdf3e93043 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableLastStageSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableLastStageSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.NoSuchElementException; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableMapOptional.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableMapOptional.java index 3fdcd40a4f7..cc4ff8bdf50 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableMapOptional.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableMapOptional.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.*; @@ -18,8 +19,8 @@ import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscribers.*; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; /** * Map the upstream values into an Optional and emit its value if any. diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableSingleStageSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableSingleStageSubscriber.java index 8040ec6f5d8..8206a9a8ac6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableSingleStageSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableSingleStageSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.NoSuchElementException; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableStageSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableStageSubscriber.java index 6594b7ba5c6..66e4fddde7d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableStageSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableStageSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.concurrent.CompletableFuture; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsFlowable.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsFlowable.java index 0ac724bdf42..653642426ed 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsFlowable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsFlowable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsObservable.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsObservable.java index e7a74f0593b..404fcb8106f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeFromCompletionStage.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeFromCompletionStage.java index d8523b8ead5..45af605e968 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeFromCompletionStage.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeFromCompletionStage.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.concurrent.CompletionStage; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeMapOptional.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeMapOptional.java index 8330d5249a2..760456f2ee6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeMapOptional.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/MaybeMapOptional.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableCollectWithCollector.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableCollectWithCollector.java index 34132a01b33..980317750ee 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableCollectWithCollector.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableCollectWithCollector.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.Objects; @@ -36,9 +37,9 @@ public final class ObservableCollectWithCollector extends Observable final Observable source; - final Collector collector; + final Collector collector; - public ObservableCollectWithCollector(Observable source, Collector collector) { + public ObservableCollectWithCollector(Observable source, Collector collector) { this.source = source; this.collector = collector; } @@ -46,7 +47,7 @@ public ObservableCollectWithCollector(Observable source, Collector c @Override protected void subscribeActual(@NonNull Observer observer) { A container; - BiConsumer accumulator; + BiConsumer accumulator; Function finisher; try { diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableCollectWithCollectorSingle.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableCollectWithCollectorSingle.java index a919b02ab9e..fa1ccd9c8fb 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableCollectWithCollectorSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableCollectWithCollectorSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.Objects; @@ -36,9 +37,9 @@ public final class ObservableCollectWithCollectorSingle extends Single< final Observable source; - final Collector collector; + final Collector collector; - public ObservableCollectWithCollectorSingle(Observable source, Collector collector) { + public ObservableCollectWithCollectorSingle(Observable source, Collector collector) { this.source = source; this.collector = collector; } @@ -51,7 +52,7 @@ public Observable fuseToObservable() { @Override protected void subscribeActual(@NonNull SingleObserver observer) { A container; - BiConsumer accumulator; + BiConsumer accumulator; Function finisher; try { diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFirstStageObserver.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFirstStageObserver.java index cda0073067c..6ac5ae51f10 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFirstStageObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFirstStageObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.NoSuchElementException; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFlatMapStream.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFlatMapStream.java index 210d920aad5..72bbea2a3f9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFlatMapStream.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFlatMapStream.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromCompletionStage.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromCompletionStage.java index 262da56026e..11a5a6307ce 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromCompletionStage.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromCompletionStage.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.concurrent.CompletionStage; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromStream.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromStream.java index 90d76813037..169eeb0bcc1 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromStream.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromStream.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.*; @@ -20,7 +21,7 @@ import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.internal.disposables.EmptyDisposable; -import io.reactivex.rxjava3.internal.fuseable.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueDisposable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableLastStageObserver.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableLastStageObserver.java index e2f9dc2225d..b35ab3dba99 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableLastStageObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableLastStageObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.NoSuchElementException; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableMapOptional.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableMapOptional.java index eb134482be6..a51ef1af287 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableMapOptional.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableMapOptional.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableSingleStageObserver.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableSingleStageObserver.java index fa8714397a6..c506fc36d41 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableSingleStageObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableSingleStageObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.NoSuchElementException; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableStageObserver.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableStageObserver.java index 54acae086f9..4025890f171 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableStageObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ObservableStageObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.concurrent.CompletableFuture; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelCollector.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelCollector.java index c8802de3f68..7fefa11e802 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelCollector.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelCollector.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelFlatMapStream.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelFlatMapStream.java index 3f38d1fec38..beae3fee367 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelFlatMapStream.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelFlatMapStream.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapOptional.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapOptional.java index 350f59f2b24..a31be9a75ef 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapOptional.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapOptional.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,8 +19,8 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; import io.reactivex.rxjava3.parallel.ParallelFlowable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapTryOptional.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapTryOptional.java index a2d454c9942..d463c7bbab9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapTryOptional.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapTryOptional.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,8 +19,8 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; import io.reactivex.rxjava3.parallel.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsFlowable.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsFlowable.java index d7286d59329..8ed45d40b95 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsFlowable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsFlowable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsObservable.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsObservable.java index 81b2d5fd7b9..4733474f138 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleFromCompletionStage.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleFromCompletionStage.java index f1be64375ec..126a096a267 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleFromCompletionStage.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleFromCompletionStage.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.jdk8; import java.util.concurrent.CompletionStage; diff --git a/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleMapOptional.java b/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleMapOptional.java index 9ee9a6f803f..ad54068d341 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleMapOptional.java +++ b/src/main/java/io/reactivex/rxjava3/internal/jdk8/SingleMapOptional.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/AbstractDisposableAutoRelease.java b/src/main/java/io/reactivex/rxjava3/internal/observers/AbstractDisposableAutoRelease.java new file mode 100644 index 00000000000..e5d89a4502f --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/AbstractDisposableAutoRelease.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +/* + * Copyright 2016-2019 David Karnok + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import java.util.concurrent.atomic.AtomicReference; + +import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.disposables.DisposableHelper; +import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.observers.LambdaConsumerIntrospection; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + +/** + * Wraps lambda callbacks and when the upstream terminates or the observer gets disposed, + * removes itself from a {@link io.reactivex.rxjava3.disposables.CompositeDisposable}. + *

History: 0.18.0 @ RxJavaExtensions + * @since 3.1.0 + */ +abstract class AbstractDisposableAutoRelease +extends AtomicReference +implements Disposable, LambdaConsumerIntrospection { + + private static final long serialVersionUID = 8924480688481408726L; + + final AtomicReference composite; + + final Consumer onError; + + final Action onComplete; + + AbstractDisposableAutoRelease( + DisposableContainer composite, + Consumer onError, + Action onComplete + ) { + this.onError = onError; + this.onComplete = onComplete; + this.composite = new AtomicReference<>(composite); + } + + public final void onError(Throwable t) { + if (get() != DisposableHelper.DISPOSED) { + lazySet(DisposableHelper.DISPOSED); + try { + onError.accept(t); + } catch (Throwable e) { + Exceptions.throwIfFatal(e); + RxJavaPlugins.onError(new CompositeException(t, e)); + } + } else { + RxJavaPlugins.onError(t); + } + removeSelf(); + } + + public final void onComplete() { + if (get() != DisposableHelper.DISPOSED) { + lazySet(DisposableHelper.DISPOSED); + try { + onComplete.run(); + } catch (Throwable e) { + Exceptions.throwIfFatal(e); + RxJavaPlugins.onError(e); + } + } + removeSelf(); + } + + @Override + public final void dispose() { + DisposableHelper.dispose(this); + removeSelf(); + } + + final void removeSelf() { + DisposableContainer c = composite.getAndSet(null); + if (c != null) { + c.delete(this); + } + } + + @Override + public final boolean isDisposed() { + return DisposableHelper.isDisposed(get()); + } + + public final void onSubscribe(Disposable d) { + DisposableHelper.setOnce(this, d); + } + + @Override + public final boolean hasCustomOnError() { + return onError != Functions.ON_ERROR_MISSING; + } + +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/BasicFuseableObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/BasicFuseableObserver.java index 0beef61824e..6bd12f39403 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/BasicFuseableObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/BasicFuseableObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,7 +17,7 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueDisposable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/BasicIntQueueDisposable.java b/src/main/java/io/reactivex/rxjava3/internal/observers/BasicIntQueueDisposable.java index 84a5c017b58..726db3ae96f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/BasicIntQueueDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/BasicIntQueueDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,7 +15,7 @@ import java.util.concurrent.atomic.AtomicInteger; -import io.reactivex.rxjava3.internal.fuseable.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueDisposable; /** * An abstract QueueDisposable implementation, extending an AtomicInteger, diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/BasicQueueDisposable.java b/src/main/java/io/reactivex/rxjava3/internal/observers/BasicQueueDisposable.java index fb6fc08366d..0daaf520a57 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/BasicQueueDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/BasicQueueDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,7 +13,7 @@ package io.reactivex.rxjava3.internal.observers; -import io.reactivex.rxjava3.internal.fuseable.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueDisposable; /** * An abstract QueueDisposable implementation that defaults all diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/BiConsumerSingleObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/BiConsumerSingleObserver.java index 2fb0221f641..1e9696cb15e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/BiConsumerSingleObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/BiConsumerSingleObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingBaseObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingBaseObserver.java index 9a128799d53..93ce06eedf1 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingBaseObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingBaseObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.observers; import java.util.concurrent.CountDownLatch; diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingDisposableMultiObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingDisposableMultiObserver.java new file mode 100644 index 00000000000..a2334c21bac --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingDisposableMultiObserver.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import java.util.concurrent.CountDownLatch; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.internal.disposables.*; +import io.reactivex.rxjava3.internal.util.BlockingHelper; + +/** + * Blocks until the upstream terminates and dispatches the outcome to + * the actual observer. + * + * @param the element type of the source + * @since 3.0.0 + */ +public final class BlockingDisposableMultiObserver +extends CountDownLatch +implements MaybeObserver, SingleObserver, CompletableObserver, Disposable { + + T value; + Throwable error; + + final SequentialDisposable upstream; + + public BlockingDisposableMultiObserver() { + super(1); + upstream = new SequentialDisposable(); + } + + @Override + public void dispose() { + upstream.dispose(); + countDown(); + } + + @Override + public boolean isDisposed() { + return upstream.isDisposed(); + } + + @Override + public void onSubscribe(@NonNull Disposable d) { + DisposableHelper.setOnce(upstream, d); + } + + @Override + public void onSuccess(@NonNull T t) { + this.value = t; + upstream.lazySet(Disposable.disposed()); + countDown(); + } + + @Override + public void onError(@NonNull Throwable e) { + this.error = e; + upstream.lazySet(Disposable.disposed()); + countDown(); + } + + @Override + public void onComplete() { + upstream.lazySet(Disposable.disposed()); + countDown(); + } + + public void blockingConsume(CompletableObserver observer) { + if (getCount() != 0) { + try { + BlockingHelper.verifyNonBlocking(); + await(); + } catch (InterruptedException ex) { + dispose(); + observer.onError(ex); + return; + } + } + if (isDisposed()) { + return; + } + + Throwable ex = error; + if (ex != null) { + observer.onError(ex); + } else { + observer.onComplete(); + } + } + + public void blockingConsume(SingleObserver observer) { + if (getCount() != 0) { + try { + BlockingHelper.verifyNonBlocking(); + await(); + } catch (InterruptedException ex) { + dispose(); + observer.onError(ex); + return; + } + } + if (isDisposed()) { + return; + } + + Throwable ex = error; + if (ex != null) { + observer.onError(ex); + } else { + observer.onSuccess(value); + } + } + + public void blockingConsume(MaybeObserver observer) { + if (getCount() != 0) { + try { + BlockingHelper.verifyNonBlocking(); + await(); + } catch (InterruptedException ex) { + dispose(); + observer.onError(ex); + return; + } + } + if (isDisposed()) { + return; + } + + Throwable ex = error; + if (ex != null) { + observer.onError(ex); + } else { + T v = value; + if (v == null) { + observer.onComplete(); + } else { + observer.onSuccess(v); + } + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingFirstObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingFirstObserver.java index 276848afe46..570000a55a0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingFirstObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingFirstObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingLastObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingLastObserver.java index bf745d3ed1b..c8e979cc313 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingLastObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingLastObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingMultiObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingMultiObserver.java index 1f4ee305bdc..458e6db5a14 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingMultiObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingMultiObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,7 +17,10 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** * A combined Observer that awaits the success or error signal via a CountDownLatch. @@ -143,4 +146,39 @@ public boolean blockingAwait(long timeout, TimeUnit unit) { } return true; } + + /** + * Blocks until the source completes and calls the appropriate callback. + * @param onSuccess for a succeeding source + * @param onError for a failing source + * @param onComplete for an empty source + */ + public void blockingConsume(Consumer onSuccess, Consumer onError, Action onComplete) { + try { + if (getCount() != 0) { + try { + BlockingHelper.verifyNonBlocking(); + await(); + } catch (InterruptedException ex) { + dispose(); + onError.accept(ex); + return; + } + } + Throwable ex = error; + if (ex != null) { + onError.accept(ex); + return; + } + T v = value; + if (v != null) { + onSuccess.accept(v); + } else { + onComplete.run(); + } + } catch (Throwable t) { + Exceptions.throwIfFatal(t); + RxJavaPlugins.onError(t); + } + } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingObserver.java index da38180751c..ff84f2a4c6f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/BlockingObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/CallbackCompletableObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/CallbackCompletableObserver.java index f6e7fed1cd9..be2da69160c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/CallbackCompletableObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/CallbackCompletableObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,33 +20,24 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; +import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.observers.LambdaConsumerIntrospection; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class CallbackCompletableObserver extends AtomicReference - implements CompletableObserver, Disposable, Consumer, LambdaConsumerIntrospection { + implements CompletableObserver, Disposable, LambdaConsumerIntrospection { private static final long serialVersionUID = -4361286194466301354L; final Consumer onError; final Action onComplete; - public CallbackCompletableObserver(Action onComplete) { - this.onError = this; - this.onComplete = onComplete; - } - public CallbackCompletableObserver(Consumer onError, Action onComplete) { this.onError = onError; this.onComplete = onComplete; } - @Override - public void accept(Throwable e) { - RxJavaPlugins.onError(new OnErrorNotImplementedException(e)); - } - @Override public void onComplete() { try { @@ -86,6 +77,6 @@ public boolean isDisposed() { @Override public boolean hasCustomOnError() { - return onError != this; + return onError != Functions.ON_ERROR_MISSING; } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/ConsumerSingleObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/ConsumerSingleObserver.java index b29a74e4bb1..eff6e4a0c1e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/ConsumerSingleObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/ConsumerSingleObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/DeferredScalarDisposable.java b/src/main/java/io/reactivex/rxjava3/internal/observers/DeferredScalarDisposable.java index 57d5f8c5c7a..084ad68571b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/DeferredScalarDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/DeferredScalarDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/DeferredScalarObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/DeferredScalarObserver.java index a99fb49a579..4453e0ffa89 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/DeferredScalarObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/DeferredScalarObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/DisposableAutoReleaseMultiObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/DisposableAutoReleaseMultiObserver.java new file mode 100644 index 00000000000..4779ff5723a --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/DisposableAutoReleaseMultiObserver.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +/* + * Copyright 2016-2019 David Karnok + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.DisposableContainer; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.disposables.DisposableHelper; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + +/** + * Wraps lambda callbacks and when the upstream terminates or this (Single | Maybe | Completable) + * observer gets disposed, removes itself from a {@link io.reactivex.rxjava3.disposables.CompositeDisposable}. + *

History: 0.18.0 @ RxJavaExtensions + * @param the element type consumed + * @since 3.1.0 + */ +public final class DisposableAutoReleaseMultiObserver +extends AbstractDisposableAutoRelease +implements SingleObserver, MaybeObserver, CompletableObserver { + + private static final long serialVersionUID = 8924480688481408726L; + + final Consumer onSuccess; + + public DisposableAutoReleaseMultiObserver( + DisposableContainer composite, + Consumer onSuccess, + Consumer onError, + Action onComplete + ) { + super(composite, onError, onComplete); + this.onSuccess = onSuccess; + } + + @Override + public void onSuccess(T t) { + if (get() != DisposableHelper.DISPOSED) { + lazySet(DisposableHelper.DISPOSED); + try { + onSuccess.accept(t); + } catch (Throwable e) { + Exceptions.throwIfFatal(e); + RxJavaPlugins.onError(e); + } + } + removeSelf(); + } + +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/DisposableAutoReleaseObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/DisposableAutoReleaseObserver.java new file mode 100644 index 00000000000..89435c96ed7 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/DisposableAutoReleaseObserver.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +/* + * Copyright 2016-2019 David Karnok + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.DisposableContainer; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.disposables.DisposableHelper; + +/** + * Wraps lambda callbacks and when the upstream terminates or this observer gets disposed, + * removes itself from a {@link io.reactivex.rxjava3.disposables.CompositeDisposable}. + *

History: 0.18.0 @ RxJavaExtensions + * @param the element type consumed + * @since 3.1.0 + */ +public final class DisposableAutoReleaseObserver +extends AbstractDisposableAutoRelease +implements Observer { + + private static final long serialVersionUID = 8924480688481408726L; + + final Consumer onNext; + + public DisposableAutoReleaseObserver( + DisposableContainer composite, + Consumer onNext, + Consumer onError, + Action onComplete + ) { + super(composite, onError, onComplete); + this.onNext = onNext; + } + + @Override + public void onNext(T t) { + if (get() != DisposableHelper.DISPOSED) { + try { + onNext.accept(t); + } catch (Throwable e) { + Exceptions.throwIfFatal(e); + get().dispose(); + onError(e); + } + } + } + +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/DisposableLambdaObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/DisposableLambdaObserver.java index 2e935140cab..529d651c677 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/DisposableLambdaObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/DisposableLambdaObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/EmptyCompletableObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/EmptyCompletableObserver.java index 36a08269c88..e92893b9bd8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/EmptyCompletableObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/EmptyCompletableObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/ForEachWhileObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/ForEachWhileObserver.java index 7017239ae0c..bed185523f2 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/ForEachWhileObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/ForEachWhileObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/FutureSingleObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/FutureMultiObserver.java similarity index 89% rename from src/main/java/io/reactivex/rxjava3/internal/observers/FutureSingleObserver.java rename to src/main/java/io/reactivex/rxjava3/internal/observers/FutureMultiObserver.java index 3e55963bea8..f109aaa5a36 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/FutureSingleObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/FutureMultiObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,7 +19,7 @@ import java.util.concurrent.atomic.AtomicReference; import io.reactivex.rxjava3.annotations.NonNull; -import io.reactivex.rxjava3.core.SingleObserver; +import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; import io.reactivex.rxjava3.internal.util.BlockingHelper; @@ -31,15 +31,15 @@ * * @param the value type */ -public final class FutureSingleObserver extends CountDownLatch -implements SingleObserver, Future, Disposable { +public final class FutureMultiObserver extends CountDownLatch +implements MaybeObserver, SingleObserver, CompletableObserver, Future, Disposable { T value; Throwable error; final AtomicReference upstream; - public FutureSingleObserver() { + public FutureMultiObserver() { super(1); this.upstream = new AtomicReference<>(); } @@ -141,6 +141,16 @@ public void onError(Throwable t) { } } + @Override + public void onComplete() { + Disposable a = upstream.get(); + if (a == DisposableHelper.DISPOSED) { + return; + } + upstream.compareAndSet(a, this); + countDown(); + } + @Override public void dispose() { // ignoring as `this` means a finished Disposable only diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/FutureObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/FutureObserver.java index 515e23e6bf6..13fd2dc9bff 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/FutureObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/FutureObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -128,22 +128,15 @@ public void onNext(T t) { @Override public void onError(Throwable t) { if (error == null) { - error = t; - - for (;;) { - Disposable a = upstream.get(); - if (a == this || a == DisposableHelper.DISPOSED) { - RxJavaPlugins.onError(t); - return; - } - if (upstream.compareAndSet(a, this)) { - countDown(); - return; - } + Disposable a = upstream.get(); + if (a != this && a != DisposableHelper.DISPOSED + && upstream.compareAndSet(a, this)) { + error = t; + countDown(); + return; } - } else { - RxJavaPlugins.onError(t); } + RxJavaPlugins.onError(t); } @Override @@ -152,15 +145,12 @@ public void onComplete() { onError(new NoSuchElementException("The source is empty")); return; } - for (;;) { - Disposable a = upstream.get(); - if (a == this || a == DisposableHelper.DISPOSED) { - return; - } - if (upstream.compareAndSet(a, this)) { - countDown(); - return; - } + Disposable a = upstream.get(); + if (a == this || a == DisposableHelper.DISPOSED) { + return; + } + if (upstream.compareAndSet(a, this)) { + countDown(); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/InnerQueuedObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/InnerQueuedObserver.java index db89a98f6e0..9d6417c0e84 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/InnerQueuedObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/InnerQueuedObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,8 +18,10 @@ import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.util.QueueDrainHelper; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; /** * Subscriber that can fuse with the upstream and calls a support interface @@ -114,8 +116,4 @@ public void setDone() { public SimpleQueue queue() { return queue; } - - public int fusionMode() { - return fusionMode; - } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/InnerQueuedObserverSupport.java b/src/main/java/io/reactivex/rxjava3/internal/observers/InnerQueuedObserverSupport.java index ff28bd092cf..01bebaf0074 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/InnerQueuedObserverSupport.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/InnerQueuedObserverSupport.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/LambdaObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/LambdaObserver.java index c52017fa4d2..6bd5dece94a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/LambdaObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/LambdaObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/QueueDrainObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/QueueDrainObserver.java index 67bc900d17d..aa25f4286c9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/QueueDrainObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/QueueDrainObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,8 +17,8 @@ import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimplePlainQueue; /** * Abstract base class for subscribers that hold another subscriber, a queue @@ -57,10 +57,6 @@ public final boolean enter() { return wip.getAndIncrement() == 0; } - public final boolean fastEnter() { - return wip.get() == 0 && wip.compareAndSet(0, 1); - } - protected final void fastPathEmit(U value, boolean delayError, Disposable dispose) { final Observer observer = downstream; final SimplePlainQueue q = queue; diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/ResumeSingleObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/ResumeSingleObserver.java index 90a29bef1c8..acaa71257cd 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/ResumeSingleObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/ResumeSingleObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/SafeCompletableObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/SafeCompletableObserver.java new file mode 100644 index 00000000000..18e16383af6 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/SafeCompletableObserver.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.CompletableObserver; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + +/** + * Wraps another {@link CompletableObserver} and catches exceptions thrown by its + * {@code onSubscribe}, {@code onError} or + * {@code onComplete} methods despite the protocol forbids it. + *

+ * Such exceptions are routed to the {@link RxJavaPlugins#onError(Throwable)} handler. + * + * @since 3.0.0 + */ +public final class SafeCompletableObserver implements CompletableObserver { + + final CompletableObserver downstream; + + boolean onSubscribeFailed; + + public SafeCompletableObserver(CompletableObserver downstream) { + this.downstream = downstream; + } + + @Override + public void onSubscribe(@NonNull Disposable d) { + try { + downstream.onSubscribe(d); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + onSubscribeFailed = true; + d.dispose(); + RxJavaPlugins.onError(ex); + } + } + + @Override + public void onError(@NonNull Throwable e) { + if (onSubscribeFailed) { + RxJavaPlugins.onError(e); + } else { + try { + downstream.onError(e); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + RxJavaPlugins.onError(new CompositeException(e, ex)); + } + } + } + + @Override + public void onComplete() { + if (!onSubscribeFailed) { + try { + downstream.onComplete(); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + RxJavaPlugins.onError(ex); + } + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/SafeMaybeObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/SafeMaybeObserver.java new file mode 100644 index 00000000000..320ac534274 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/SafeMaybeObserver.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.MaybeObserver; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + +/** + * Wraps another {@link MaybeObserver} and catches exceptions thrown by its + * {@code onSubscribe}, {@code onSuccess}, {@code onError} or + * {@code onComplete} methods despite the protocol forbids it. + *

+ * Such exceptions are routed to the {@link RxJavaPlugins#onError(Throwable)} handler. + * + * @param the element type of the sequence + * @since 3.0.0 + */ +public final class SafeMaybeObserver implements MaybeObserver { + + final MaybeObserver downstream; + + boolean onSubscribeFailed; + + public SafeMaybeObserver(MaybeObserver downstream) { + this.downstream = downstream; + } + + @Override + public void onSubscribe(@NonNull Disposable d) { + try { + downstream.onSubscribe(d); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + onSubscribeFailed = true; + d.dispose(); + RxJavaPlugins.onError(ex); + } + } + + @Override + public void onSuccess(@NonNull T t) { + if (!onSubscribeFailed) { + try { + downstream.onSuccess(t); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + RxJavaPlugins.onError(ex); + } + } + } + + @Override + public void onError(@NonNull Throwable e) { + if (onSubscribeFailed) { + RxJavaPlugins.onError(e); + } else { + try { + downstream.onError(e); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + RxJavaPlugins.onError(new CompositeException(e, ex)); + } + } + } + + @Override + public void onComplete() { + if (!onSubscribeFailed) { + try { + downstream.onComplete(); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + RxJavaPlugins.onError(ex); + } + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/SafeSingleObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/SafeSingleObserver.java new file mode 100644 index 00000000000..3e73d1e6393 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/observers/SafeSingleObserver.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.SingleObserver; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + +/** + * Wraps another {@link SingleObserver} and catches exceptions thrown by its + * {@code onSubscribe}, {@code onSuccess} or {@code onError} methods despite + * the protocol forbids it. + *

+ * Such exceptions are routed to the {@link RxJavaPlugins#onError(Throwable)} handler. + * + * @param the element type of the sequence + * @since 3.0.0 + */ +public final class SafeSingleObserver implements SingleObserver { + + final SingleObserver downstream; + + boolean onSubscribeFailed; + + public SafeSingleObserver(SingleObserver downstream) { + this.downstream = downstream; + } + + @Override + public void onSubscribe(@NonNull Disposable d) { + try { + downstream.onSubscribe(d); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + onSubscribeFailed = true; + d.dispose(); + RxJavaPlugins.onError(ex); + } + } + + @Override + public void onSuccess(@NonNull T t) { + if (!onSubscribeFailed) { + try { + downstream.onSuccess(t); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + RxJavaPlugins.onError(ex); + } + } + } + + @Override + public void onError(@NonNull Throwable e) { + if (onSubscribeFailed) { + RxJavaPlugins.onError(e); + } else { + try { + downstream.onError(e); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + RxJavaPlugins.onError(new CompositeException(e, ex)); + } + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/observers/SubscriberCompletableObserver.java b/src/main/java/io/reactivex/rxjava3/internal/observers/SubscriberCompletableObserver.java deleted file mode 100644 index 2bbc5128d67..00000000000 --- a/src/main/java/io/reactivex/rxjava3/internal/observers/SubscriberCompletableObserver.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2016-present, RxJava Contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See - * the License for the specific language governing permissions and limitations under the License. - */ - -package io.reactivex.rxjava3.internal.observers; - -import org.reactivestreams.*; - -import io.reactivex.rxjava3.core.CompletableObserver; -import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.internal.disposables.DisposableHelper; - -public final class SubscriberCompletableObserver implements CompletableObserver, Subscription { - final Subscriber subscriber; - - Disposable upstream; - - public SubscriberCompletableObserver(Subscriber subscriber) { - this.subscriber = subscriber; - } - - @Override - public void onComplete() { - subscriber.onComplete(); - } - - @Override - public void onError(Throwable e) { - subscriber.onError(e); - } - - @Override - public void onSubscribe(Disposable d) { - if (DisposableHelper.validate(this.upstream, d)) { - this.upstream = d; - - subscriber.onSubscribe(this); - } - } - - @Override - public void request(long n) { - // ignored, no values emitted anyway - } - - @Override - public void cancel() { - upstream.dispose(); - } -} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAmb.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAmb.java index 14e8ae464b3..60fa3ce4c6d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAmb.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAmb.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenCompletable.java index d006329aeab..13e582e7646 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCache.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCache.java index da002c0dd6c..c5fd3279d63 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCache.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCache.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcat.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcat.java index c16b847c584..00a53f3ad73 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcat.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcat.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,9 +21,8 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.*; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.operators.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class CompletableConcat extends Completable { @@ -121,7 +120,7 @@ public void onSubscribe(Subscription s) { public void onNext(CompletableSource t) { if (sourceFused == QueueSubscription.NONE) { if (!queue.offer(t)) { - onError(new MissingBackpressureException()); + onError(new QueueOverflowException()); return; } } @@ -182,9 +181,8 @@ void drain() { boolean empty = cs == null; if (d && empty) { - if (once.compareAndSet(false, true)) { - downstream.onComplete(); - } + // errors never set done or call drain. + downstream.onComplete(); return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatArray.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatArray.java index c423c375875..e87968e7749 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatArray.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatArray.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatIterable.java index ef801a16461..73510018ffd 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCreate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCreate.java index 40046307563..b721cbb351e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCreate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCreate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDefer.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDefer.java index c451413f490..2a7763bb525 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDefer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDefer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDelay.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDelay.java index 49c25bf6e11..c21134569bc 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDelay.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDelay.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDetach.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDetach.java index efd28228fa1..d01d297495a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDetach.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDetach.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDisposeOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDisposeOn.java index 16f9fa159c9..bd213b5fc4c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDisposeOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDisposeOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoFinally.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoFinally.java index 425ed4caea8..02fa08cdb04 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoFinally.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoFinally.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoOnEvent.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoOnEvent.java index 63a408efc42..dfa24b000f8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoOnEvent.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoOnEvent.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableEmpty.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableEmpty.java index e18ccc9421a..7c18a4ddc9a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableEmpty.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableEmpty.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableError.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableError.java index 70d4e410064..8d2cb2fcc2a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableError.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableError.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableErrorSupplier.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableErrorSupplier.java index bd4250c447c..80c95806b84 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableErrorSupplier.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableErrorSupplier.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromAction.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromAction.java index 4cd7fb479cc..53cfc2615bd 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromAction.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromAction.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -31,19 +31,21 @@ public CompletableFromAction(Action run) { protected void subscribeActual(CompletableObserver observer) { Disposable d = Disposable.empty(); observer.onSubscribe(d); - try { - run.run(); - } catch (Throwable e) { - Exceptions.throwIfFatal(e); + if (!d.isDisposed()) { + try { + run.run(); + } catch (Throwable e) { + Exceptions.throwIfFatal(e); + if (!d.isDisposed()) { + observer.onError(e); + } else { + RxJavaPlugins.onError(e); + } + return; + } if (!d.isDisposed()) { - observer.onError(e); - } else { - RxJavaPlugins.onError(e); + observer.onComplete(); } - return; - } - if (!d.isDisposed()) { - observer.onComplete(); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromCallable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromCallable.java index 57764950df3..90f9266934a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromCallable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromCallable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromObservable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromObservable.java index d91133e5027..25dffbbebf4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromPublisher.java index 6baeb7a87e4..4205d1141c4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromRunnable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromRunnable.java index e94d650310b..79f2efb4708 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromRunnable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromRunnable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,19 +30,21 @@ public CompletableFromRunnable(Runnable runnable) { protected void subscribeActual(CompletableObserver observer) { Disposable d = Disposable.empty(); observer.onSubscribe(d); - try { - runnable.run(); - } catch (Throwable e) { - Exceptions.throwIfFatal(e); + if (!d.isDisposed()) { + try { + runnable.run(); + } catch (Throwable e) { + Exceptions.throwIfFatal(e); + if (!d.isDisposed()) { + observer.onError(e); + } else { + RxJavaPlugins.onError(e); + } + return; + } if (!d.isDisposed()) { - observer.onError(e); - } else { - RxJavaPlugins.onError(e); + observer.onComplete(); } - return; - } - if (!d.isDisposed()) { - observer.onComplete(); } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSingle.java index b035f142d99..d55fc303398 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSupplier.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSupplier.java index e3e29188a0f..8b45e6b5f09 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSupplier.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSupplier.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromUnsafeSource.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromUnsafeSource.java index 02857d46923..dfc0356bf7b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromUnsafeSource.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromUnsafeSource.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableHide.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableHide.java index 16708ee90ed..536855a7b7c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableHide.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableHide.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableLift.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableLift.java index 58356a73ddd..6749689bccb 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableLift.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableLift.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMaterialize.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMaterialize.java index 15dd320cad4..198ba94b1a6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMaterialize.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMaterialize.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMerge.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMerge.java index 9d916d84b6b..2528fe2f3bb 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMerge.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMerge.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeArray.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeArray.java index ec9c6752102..56095221cca 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeArray.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeArray.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -86,9 +86,8 @@ public void onError(Throwable e) { @Override public void onComplete() { if (decrementAndGet() == 0) { - if (once.compareAndSet(false, true)) { - downstream.onComplete(); - } + // errors don't decrement this + downstream.onComplete(); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeDelayErrorArray.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeArrayDelayError.java similarity index 96% rename from src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeDelayErrorArray.java rename to src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeArrayDelayError.java index 549fd10a48d..85b4c612258 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeDelayErrorArray.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeArrayDelayError.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,11 +19,11 @@ import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.internal.util.AtomicThrowable; -public final class CompletableMergeDelayErrorArray extends Completable { +public final class CompletableMergeArrayDelayError extends Completable { final CompletableSource[] sources; - public CompletableMergeDelayErrorArray(CompletableSource[] sources) { + public CompletableMergeArrayDelayError(CompletableSource[] sources) { this.sources = sources; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeDelayErrorIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeDelayErrorIterable.java index 55efbd8915a..cb629747539 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeDelayErrorIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeDelayErrorIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,7 +20,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.CompositeDisposable; import io.reactivex.rxjava3.exceptions.Exceptions; -import io.reactivex.rxjava3.internal.operators.completable.CompletableMergeDelayErrorArray.*; +import io.reactivex.rxjava3.internal.operators.completable.CompletableMergeArrayDelayError.*; import io.reactivex.rxjava3.internal.util.AtomicThrowable; public final class CompletableMergeDelayErrorIterable extends Completable { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeIterable.java index b0e5b87bf79..3f2dce90e13 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -128,9 +128,8 @@ public void onError(Throwable e) { @Override public void onComplete() { if (wip.decrementAndGet() == 0) { - if (compareAndSet(false, true)) { - downstream.onComplete(); - } + // errors don't decrement wip + downstream.onComplete(); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableNever.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableNever.java index 8c11621a7cd..17bc2cc140c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableNever.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableNever.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableObserveOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableObserveOn.java index 8bccc8ced0d..b48ade189fe 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableObserveOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableObserveOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableOnErrorComplete.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableOnErrorComplete.java index 6d87a4275e1..c4252e7f3b4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableOnErrorComplete.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableOnErrorComplete.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -32,15 +32,18 @@ public CompletableOnErrorComplete(CompletableSource source, Predicate predicate; - OnError(CompletableObserver observer) { + OnError(CompletableObserver observer, + Predicate predicate) { this.downstream = observer; + this.predicate = predicate; } @Override diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableOnErrorReturn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableOnErrorReturn.java new file mode 100644 index 00000000000..9cd91262a55 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableOnErrorReturn.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.completable; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.internal.disposables.DisposableHelper; + +import java.util.Objects; + +/** + * Returns a value generated via a function if the main source signals an onError. + * @param the value type + * @since 3.0.0 + */ +public final class CompletableOnErrorReturn extends Maybe { + + final CompletableSource source; + + final Function valueSupplier; + + public CompletableOnErrorReturn(CompletableSource source, + Function valueSupplier) { + this.source = source; + this.valueSupplier = valueSupplier; + } + + @Override + protected void subscribeActual(MaybeObserver observer) { + source.subscribe(new OnErrorReturnMaybeObserver<>(observer, valueSupplier)); + } + + static final class OnErrorReturnMaybeObserver implements CompletableObserver, Disposable { + + final MaybeObserver downstream; + + final Function itemSupplier; + + Disposable upstream; + + OnErrorReturnMaybeObserver(MaybeObserver actual, + Function itemSupplier) { + this.downstream = actual; + this.itemSupplier = itemSupplier; + } + + @Override + public void dispose() { + upstream.dispose(); + } + + @Override + public boolean isDisposed() { + return upstream.isDisposed(); + } + + @Override + public void onSubscribe(Disposable d) { + if (DisposableHelper.validate(this.upstream, d)) { + this.upstream = d; + + downstream.onSubscribe(this); + } + } + + @Override + public void onError(Throwable e) { + T v; + + try { + v = Objects.requireNonNull(itemSupplier.apply(e), "The itemSupplier returned a null value"); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + downstream.onError(new CompositeException(e, ex)); + return; + } + + downstream.onSuccess(v); + } + + @Override + public void onComplete() { + downstream.onComplete(); + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletablePeek.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletablePeek.java index 04955c69311..aeba5381b55 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletablePeek.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletablePeek.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableResumeNext.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableResumeNext.java index 1d3bd7a3a0c..785501511a6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableResumeNext.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableResumeNext.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSubscribeOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSubscribeOn.java index f76ac93595b..748602f9780 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSubscribeOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSubscribeOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTakeUntilCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTakeUntilCompletable.java index bd7e519a170..364484ab10b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTakeUntilCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTakeUntilCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimeout.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimeout.java index 1a38bb383a1..80f40dfd723 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimeout.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimeout.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimer.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimer.java index 4e271af7739..b50fd5db2ed 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToFlowable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToFlowable.java index 9ad0d0a8d88..346267ce134 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToFlowable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToFlowable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,7 +16,7 @@ import org.reactivestreams.Subscriber; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.internal.observers.SubscriberCompletableObserver; +import io.reactivex.rxjava3.internal.operators.flowable.FlowableFromCompletable; public final class CompletableToFlowable extends Flowable { @@ -28,7 +28,6 @@ public CompletableToFlowable(CompletableSource source) { @Override protected void subscribeActual(Subscriber s) { - SubscriberCompletableObserver os = new SubscriberCompletableObserver<>(s); - source.subscribe(os); + source.subscribe(new FlowableFromCompletable.FromCompletableObserver<>(s)); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToObservable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToObservable.java index 095a975dbf6..ccf1a9e5047 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,9 +14,7 @@ package io.reactivex.rxjava3.internal.operators.completable; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.observers.BasicQueueDisposable; +import io.reactivex.rxjava3.internal.operators.observable.ObservableFromCompletable; /** * Wraps a Completable and exposes it as an Observable. @@ -33,66 +31,6 @@ public CompletableToObservable(CompletableSource source) { @Override protected void subscribeActual(Observer observer) { - source.subscribe(new ObserverCompletableObserver(observer)); - } - - static final class ObserverCompletableObserver extends BasicQueueDisposable - implements CompletableObserver { - - final Observer observer; - - Disposable upstream; - - ObserverCompletableObserver(Observer observer) { - this.observer = observer; - } - - @Override - public void onComplete() { - observer.onComplete(); - } - - @Override - public void onError(Throwable e) { - observer.onError(e); - } - - @Override - public void onSubscribe(Disposable d) { - if (DisposableHelper.validate(upstream, d)) { - this.upstream = d; - observer.onSubscribe(this); - } - } - - @Override - public int requestFusion(int mode) { - return mode & ASYNC; - } - - @Override - public Void poll() { - return null; // always empty - } - - @Override - public boolean isEmpty() { - return true; - } - - @Override - public void clear() { - // always empty - } - - @Override - public void dispose() { - upstream.dispose(); - } - - @Override - public boolean isDisposed() { - return upstream.isDisposed(); - } + source.subscribe(new ObservableFromCompletable.FromCompletableObserver<>(observer)); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToSingle.java index c35d909796e..58e47247dfc 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableUsing.java b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableUsing.java index 3476a65b254..648e6529e23 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableUsing.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/completable/CompletableUsing.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/AbstractBackpressureThrottlingSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/AbstractBackpressureThrottlingSubscriber.java new file mode 100644 index 00000000000..62c7d07a88d --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/AbstractBackpressureThrottlingSubscriber.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import io.reactivex.rxjava3.core.FlowableSubscriber; +import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Abstract base class for operators that throttle excessive updates from upstream in case if + * downstream {@link Subscriber} is not ready to receive updates. + * + * @param the upstream value type + * @param the downstream value type + */ +abstract class AbstractBackpressureThrottlingSubscriber extends AtomicInteger implements FlowableSubscriber, Subscription { + + private static final long serialVersionUID = -5050301752721603566L; + + final Subscriber downstream; + + Subscription upstream; + + volatile boolean done; + Throwable error; + + volatile boolean cancelled; + + final AtomicLong requested = new AtomicLong(); + + final AtomicReference current = new AtomicReference<>(); + + AbstractBackpressureThrottlingSubscriber(Subscriber downstream) { + this.downstream = downstream; + } + + @Override + public void onSubscribe(Subscription s) { + if (SubscriptionHelper.validate(this.upstream, s)) { + this.upstream = s; + downstream.onSubscribe(this); + s.request(Long.MAX_VALUE); + } + } + + @Override + public abstract void onNext(T t); + + @Override + public void onError(Throwable t) { + error = t; + done = true; + drain(); + } + + @Override + public void onComplete() { + done = true; + drain(); + } + + @Override + public void request(long n) { + if (SubscriptionHelper.validate(n)) { + BackpressureHelper.add(requested, n); + drain(); + } + } + + @Override + public void cancel() { + if (!cancelled) { + cancelled = true; + upstream.cancel(); + + if (getAndIncrement() == 0) { + current.lazySet(null); + } + } + } + + void drain() { + if (getAndIncrement() != 0) { + return; + } + final Subscriber a = downstream; + int missed = 1; + final AtomicLong r = requested; + final AtomicReference q = current; + + for (;;) { + long e = 0L; + + while (e != r.get()) { + boolean d = done; + R v = q.getAndSet(null); + boolean empty = v == null; + + if (checkTerminated(d, empty, a, q)) { + return; + } + + if (empty) { + break; + } + + a.onNext(v); + + e++; + } + + if (e == r.get() && checkTerminated(done, q.get() == null, a, q)) { + return; + } + + if (e != 0L) { + BackpressureHelper.produced(r, e); + } + + missed = addAndGet(-missed); + if (missed == 0) { + break; + } + } + } + + boolean checkTerminated(boolean d, boolean empty, Subscriber a, AtomicReference q) { + if (cancelled) { + q.lazySet(null); + return true; + } + + if (d) { + Throwable e = error; + if (e != null) { + q.lazySet(null); + a.onError(e); + return true; + } else + if (empty) { + a.onComplete(); + return true; + } + } + + return false; + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/AbstractFlowableWithUpstream.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/AbstractFlowableWithUpstream.java index d83f65c3474..4a9484f7434 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/AbstractFlowableWithUpstream.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/AbstractFlowableWithUpstream.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableIterable.java index 51015ce9189..11239d04a7a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,9 +22,9 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SpscArrayQueue; public final class BlockingFlowableIterable implements Iterable { final Flowable source; @@ -138,9 +138,12 @@ public void onSubscribe(Subscription s) { @Override public void onNext(T t) { if (!queue.offer(t)) { + // Error must be set first before calling cancel to avoid race + // with hasNext(), which checks for cancel first before checking + // for error. + error = new QueueOverflowException(); SubscriptionHelper.cancel(this); - - onError(new MissingBackpressureException("Queue full?!")); + onComplete(); } else { signalConsumer(); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableLatest.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableLatest.java index 1cc469a1b9b..7628776ae06 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableLatest.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableLatest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableMostRecent.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableMostRecent.java index bfd206eea9c..7c41634c555 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableMostRecent.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableMostRecent.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,7 +23,7 @@ * Returns an Iterable that always returns the item most recently emitted by an Observable, or a * seed value if no item has yet been emitted. *

- * + * * * @param the value type */ diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableNext.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableNext.java index 57ca264f0cf..9704d2d2103 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableNext.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableNext.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,7 +27,7 @@ /** * Returns an Iterable that blocks until the Observable emits another item, then returns that item. *

- * + * * * @param the value type */ @@ -99,11 +99,8 @@ private boolean moveToNext() { if (nextNotification.isOnComplete()) { return false; } - if (nextNotification.isOnError()) { - error = nextNotification.getError(); - throw ExceptionHelper.wrapOrThrow(error); - } - throw new IllegalStateException("Should not reach here"); + error = nextNotification.getError(); + throw ExceptionHelper.wrapOrThrow(error); } catch (InterruptedException e) { subscriber.dispose(); error = e; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAll.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAll.java index 84ea50cbf7d..7f8271733de 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAll.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAll.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import org.reactivestreams.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAllSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAllSingle.java index 8d1bf998efc..03d269e738a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAllSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAllSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import org.reactivestreams.Subscription; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAmb.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAmb.java index ff650b5719b..5646fdb9937 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAmb.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAmb.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAny.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAny.java index d0adcb6dbe1..b09dce4c03e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAny.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAny.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import org.reactivestreams.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAnySingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAnySingle.java index 7ca8a6b4286..1b210b82d46 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAnySingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAnySingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import org.reactivestreams.Subscription; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAutoConnect.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAutoConnect.java index c8bb4a7d1a5..8d4b428c2b9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAutoConnect.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAutoConnect.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBlockingSubscribe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBlockingSubscribe.java index 9caafbc8e5e..22cede1410c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBlockingSubscribe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBlockingSubscribe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -36,17 +36,17 @@ private FlowableBlockingSubscribe() { /** * Subscribes to the source and calls the Subscriber methods on the current thread. *

- * @param o the source publisher + * @param source the source publisher * The cancellation and backpressure is composed through. * @param subscriber the subscriber to forward events and calls to in the current thread * @param the value type */ - public static void subscribe(Publisher o, Subscriber subscriber) { + public static void subscribe(Publisher source, Subscriber subscriber) { final BlockingQueue queue = new LinkedBlockingQueue<>(); BlockingSubscriber bs = new BlockingSubscriber<>(queue); - o.subscribe(bs); + source.subscribe(bs); try { for (;;) { @@ -77,15 +77,15 @@ public static void subscribe(Publisher o, Subscriber /** * Runs the source observable to a terminal event, ignoring any values and rethrowing any exception. - * @param o the source publisher + * @param source the source to await * @param the value type */ - public static void subscribe(Publisher o) { + public static void subscribe(Publisher source) { BlockingIgnoringReceiver callback = new BlockingIgnoringReceiver(); LambdaSubscriber ls = new LambdaSubscriber<>(Functions.emptyConsumer(), callback, callback, Functions.REQUEST_MAX); - o.subscribe(ls); + source.subscribe(ls); BlockingHelper.awaitForComplete(callback, ls); Throwable e = callback.error; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBuffer.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBuffer.java index 04f5ae182e5..a1cb792f08b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBuffer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBuffer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -133,6 +133,7 @@ public void onError(Throwable t) { RxJavaPlugins.onError(t); return; } + buffer = null; done = true; downstream.onError(t); } @@ -145,8 +146,9 @@ public void onComplete() { done = true; C b = buffer; + buffer = null; - if (b != null && !b.isEmpty()) { + if (b != null) { downstream.onNext(b); } downstream.onComplete(); @@ -390,7 +392,7 @@ public void onNext(T t) { C b = bs.peek(); - if (b != null && b.size() + 1 == size) { + if (b.size() + 1 == size) { bs.poll(); b.add(t); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferBoundary.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferBoundary.java index 251144a1d23..b009b1bc250 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferBoundary.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferBoundary.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,9 +22,9 @@ import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class FlowableBufferBoundary, Open, Close> diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferExactBoundary.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferExactBoundary.java index 8d23e3c7bc1..3e2abefdd98 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferExactBoundary.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferExactBoundary.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,7 +45,7 @@ protected void subscribeActual(Subscriber s) { } static final class BufferExactBoundarySubscriber, B> - extends QueueDrainSubscriber implements FlowableSubscriber, Subscription, Disposable { + extends QueueDrainSubscriber implements Subscription, Disposable { final Supplier bufferSupplier; final Publisher boundary; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferTimed.java index 854e0460ede..89749acaefc 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCache.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCache.java index 25d5fb71a32..ee52769e699 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCache.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCache.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCollect.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCollect.java index b8751a23f90..8f45d624042 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCollect.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCollect.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import org.reactivestreams.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCollectSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCollectSingle.java index f159911fba0..714bc92eea1 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCollectSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCollectSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import org.reactivestreams.Subscription; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCombineLatest.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCombineLatest.java index 392de62d220..ac947b9541c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCombineLatest.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCombineLatest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,7 +13,6 @@ package io.reactivex.rxjava3.internal.operators.flowable; -import java.util.Iterator; import java.util.Objects; import java.util.concurrent.atomic.*; @@ -24,9 +23,9 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.operators.flowable.FlowableMap.MapSubscriber; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** @@ -73,75 +72,46 @@ public FlowableCombineLatest(@NonNull Iterable> @SuppressWarnings("unchecked") @Override public void subscribeActual(Subscriber s) { - Publisher[] a = array; - int n; - if (a == null) { - n = 0; - a = new Publisher[8]; - - Iterator> it; + Publisher[] sources = array; + int count; + if (sources == null) { + count = 0; + sources = new Publisher[8]; try { - it = Objects.requireNonNull(iterable.iterator(), "The iterator returned is null"); - } catch (Throwable e) { - Exceptions.throwIfFatal(e); - EmptySubscription.error(e, s); - return; - } - - for (;;) { - - boolean b; - - try { - b = it.hasNext(); - } catch (Throwable e) { - Exceptions.throwIfFatal(e); - EmptySubscription.error(e, s); - return; - } - - if (!b) { - break; - } - - Publisher p; - - try { - p = Objects.requireNonNull(it.next(), "The publisher returned by the iterator is null"); - } catch (Throwable e) { - Exceptions.throwIfFatal(e); - EmptySubscription.error(e, s); - return; - } - - if (n == a.length) { - Publisher[] c = new Publisher[n + (n >> 2)]; - System.arraycopy(a, 0, c, 0, n); - a = c; + for (Publisher p : iterable) { + if (count == sources.length) { + Publisher[] b = new Publisher[count + (count >> 2)]; + System.arraycopy(sources, 0, b, 0, count); + sources = b; + } + sources[count++] = Objects.requireNonNull(p, "The Iterator returned a null Publisher"); } - a[n++] = p; + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + EmptySubscription.error(ex, s); + return; } } else { - n = a.length; + count = sources.length; } - if (n == 0) { + if (count == 0) { EmptySubscription.complete(s); return; } - if (n == 1) { - a[0].subscribe(new MapSubscriber<>(s, new SingletonArrayFunc())); + if (count == 1) { + sources[0].subscribe(new MapSubscriber<>(s, new SingletonArrayFunc())); return; } CombineLatestCoordinator coordinator = - new CombineLatestCoordinator<>(s, combiner, n, bufferSize, delayErrors); + new CombineLatestCoordinator<>(s, combiner, count, bufferSize, delayErrors); s.onSubscribe(coordinator); - coordinator.subscribe(a, n); + coordinator.subscribe(sources, count); } static final class CombineLatestCoordinator @@ -173,7 +143,7 @@ static final class CombineLatestCoordinator volatile boolean done; - final AtomicReference error; + final AtomicThrowable error; CombineLatestCoordinator(Subscriber actual, Function combiner, int n, @@ -189,7 +159,7 @@ static final class CombineLatestCoordinator this.latest = new Object[n]; this.queue = new SpscLinkedArrayQueue<>(bufferSize); this.requested = new AtomicLong(); - this.error = new AtomicReference<>(); + this.error = new AtomicThrowable(); this.delayErrors = delayErrors; } @@ -205,6 +175,7 @@ public void request(long n) { public void cancel() { cancelled = true; cancelAll(); + drain(); } void subscribe(Publisher[] sources, int n) { @@ -411,6 +382,7 @@ boolean checkTerminated(boolean d, boolean empty, Subscriber a, SpscLinkedArr if (cancelled) { cancelAll(); q.clear(); + error.tryTerminateAndReport(); return true; } @@ -418,13 +390,7 @@ boolean checkTerminated(boolean d, boolean empty, Subscriber a, SpscLinkedArr if (delayErrors) { if (empty) { cancelAll(); - Throwable e = ExceptionHelper.terminate(error); - - if (e != null && e != ExceptionHelper.TERMINATED) { - a.onError(e); - } else { - a.onComplete(); - } + error.tryTerminateConsumer(a); return true; } } else { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatArray.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatArray.java index 81834bba614..34d4248514c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatArray.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatArray.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import java.util.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMap.java index 98d8ea44107..5d1b6e4c33b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,20 +10,22 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import java.util.Objects; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.*; import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; public final class FlowableConcatMap extends AbstractFlowableWithUpstream { @@ -150,7 +152,7 @@ public final void onNext(T t) { if (sourceMode != QueueSubscription.ASYNC) { if (!queue.offer(t)) { upstream.cancel(); - onError(new IllegalStateException("Queue full?!")); + onError(new QueueOverflowException()); return; } } @@ -195,35 +197,19 @@ void subscribeActual() { @Override public void onError(Throwable t) { - if (errors.tryAddThrowableOrReport(t)) { - inner.cancel(); - - if (getAndIncrement() == 0) { - errors.tryTerminateConsumer(downstream); - } - } + inner.cancel(); + HalfSerializer.onError(downstream, t, this, errors); } @Override public void innerNext(R value) { - if (get() == 0 && compareAndSet(0, 1)) { - downstream.onNext(value); - if (compareAndSet(1, 0)) { - return; - } - errors.tryTerminateConsumer(downstream); - } + HalfSerializer.onNext(downstream, value, this, errors); } @Override public void innerError(Throwable e) { - if (errors.tryAddThrowableOrReport(e)) { - upstream.cancel(); - - if (getAndIncrement() == 0) { - errors.tryTerminateConsumer(downstream); - } - } + upstream.cancel(); + HalfSerializer.onError(downstream, e, this, errors); } @Override @@ -318,17 +304,13 @@ void drain() { } if (inner.isUnbounded()) { - if (get() == 0 && compareAndSet(0, 1)) { - downstream.onNext(vr); - if (!compareAndSet(1, 0)) { - errors.tryTerminateConsumer(downstream); - return; - } + if (!HalfSerializer.onNext(downstream, vr, this, errors)) { + return; } continue; } else { active = true; - inner.setSubscription(new WeakScalarSubscription<>(vr, inner)); + inner.setSubscription(new SimpleScalarSubscription<>(vr, inner)); } } else { @@ -345,20 +327,22 @@ void drain() { } } - static final class WeakScalarSubscription implements Subscription { + static final class SimpleScalarSubscription + extends AtomicBoolean + implements Subscription { + private static final long serialVersionUID = -7606889335172043256L; + final Subscriber downstream; final T value; - boolean once; - WeakScalarSubscription(T value, Subscriber downstream) { + SimpleScalarSubscription(T value, Subscriber downstream) { this.value = value; this.downstream = downstream; } @Override public void request(long n) { - if (n > 0 && !once) { - once = true; + if (n > 0L && compareAndSet(false, true)) { Subscriber a = downstream; a.onNext(value); a.onComplete(); @@ -527,7 +511,7 @@ void drain() { continue; } else { active = true; - inner.setSubscription(new WeakScalarSubscription<>(vr, inner)); + inner.setSubscription(new SimpleScalarSubscription<>(vr, inner)); } } else { active = true; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapEager.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapEager.java index ea39af45a24..dc423d89fc0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapEager.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapEager.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,11 +21,11 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.SimpleQueue; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.subscribers.*; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; public final class FlowableConcatMapEager extends AbstractFlowableWithUpstream { @@ -200,7 +200,7 @@ public void innerNext(InnerQueuedSubscriber inner, R value) { drain(); } else { inner.cancel(); - innerError(inner, new MissingBackpressureException()); + innerError(inner, MissingBackpressureException.createDefault()); } } @@ -318,7 +318,7 @@ public void drain() { e++; - inner.requestOne(); + inner.request(1L); } if (e == r) { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapEagerPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapEagerPublisher.java index 36d465d1908..218f90c2a69 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapEagerPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapEagerPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapScheduler.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapScheduler.java index d59677efa1e..707d10a19ea 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapScheduler.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapScheduler.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import java.util.Objects; @@ -18,13 +19,14 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.operators.flowable.FlowableConcatMap.*; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; public final class FlowableConcatMapScheduler extends AbstractFlowableWithUpstream { @@ -149,7 +151,7 @@ public final void onNext(T t) { if (sourceMode != QueueSubscription.ASYNC) { if (!queue.offer(t)) { upstream.cancel(); - onError(new IllegalStateException("Queue full?!")); + onError(new QueueOverflowException()); return; } } @@ -204,9 +206,13 @@ public void onError(Throwable t) { } } + boolean tryEnter() { + return get() == 0 && compareAndSet(0, 1); + } + @Override public void innerNext(R value) { - if (get() == 0 && compareAndSet(0, 1)) { + if (tryEnter()) { downstream.onNext(value); if (compareAndSet(1, 0)) { return; @@ -325,12 +331,12 @@ public void run() { return; } - if (vr == null) { + if (vr == null || cancelled) { continue; } if (inner.isUnbounded()) { - if (get() == 0 && compareAndSet(0, 1)) { + if (tryEnter()) { downstream.onNext(vr); if (!compareAndSet(1, 0)) { errors.tryTerminateConsumer(downstream); @@ -341,7 +347,7 @@ public void run() { continue; } else { active = true; - inner.setSubscription(new WeakScalarSubscription<>(vr, inner)); + inner.setSubscription(new SimpleScalarSubscription<>(vr, inner)); } } else { @@ -515,7 +521,7 @@ public void run() { vr = null; } - if (vr == null) { + if (vr == null || cancelled) { continue; } @@ -524,7 +530,7 @@ public void run() { continue; } else { active = true; - inner.setSubscription(new WeakScalarSubscription<>(vr, inner)); + inner.setSubscription(new SimpleScalarSubscription<>(vr, inner)); } } else { active = true; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithCompletable.java index 31729e450f0..81ac13776a8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithMaybe.java index b7db7fd0935..e82076533a4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithSingle.java index c93ee51ba8e..bfe900ab2e5 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCount.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCount.java index 7858180b09d..2c32dd4d766 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCount.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCount.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCountSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCountSingle.java index 928f36209c2..750f722dbc1 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCountSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCountSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCreate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCreate.java index b7091c31f99..1e87c4b7e65 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCreate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCreate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,10 +22,10 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.Cancellable; import io.reactivex.rxjava3.internal.disposables.*; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimplePlainQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class FlowableCreate extends Flowable { @@ -442,7 +442,7 @@ static final class ErrorAsyncEmitter extends NoOverflowBaseAsyncEmitter { @Override void onOverflow() { - onError(new MissingBackpressureException("create: could not emit value due to lack of requests")); + onError(new MissingBackpressureException("create: " + MissingBackpressureException.DEFAULT_MESSAGE)); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDebounce.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDebounce.java index 16c666b2838..51838a18645 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDebounce.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDebounce.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -148,7 +148,7 @@ void emit(long idx, T value) { BackpressureHelper.produced(this, 1); } else { cancel(); - downstream.onError(new MissingBackpressureException("Could not deliver value due to lack of requests")); + downstream.onError(MissingBackpressureException.createDefault()); } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDebounceTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDebounceTimed.java index 82ae29d4976..b9e5dff7f31 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDebounceTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDebounceTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,6 +16,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.*; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.Consumer; import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; @@ -32,19 +34,20 @@ public final class FlowableDebounceTimed extends AbstractFlowableWithUpstream final long timeout; final TimeUnit unit; final Scheduler scheduler; + final Consumer onDropped; - public FlowableDebounceTimed(Flowable source, long timeout, TimeUnit unit, Scheduler scheduler) { + public FlowableDebounceTimed(Flowable source, long timeout, TimeUnit unit, Scheduler scheduler, Consumer onDropped) { super(source); this.timeout = timeout; this.unit = unit; this.scheduler = scheduler; + this.onDropped = onDropped; } @Override protected void subscribeActual(Subscriber s) { source.subscribe(new DebounceTimedSubscriber<>( - new SerializedSubscriber<>(s), - timeout, unit, scheduler.createWorker())); + new SerializedSubscriber<>(s), timeout, unit, scheduler.createWorker(), onDropped)); } static final class DebounceTimedSubscriber extends AtomicLong @@ -55,20 +58,22 @@ static final class DebounceTimedSubscriber extends AtomicLong final long timeout; final TimeUnit unit; final Scheduler.Worker worker; + final Consumer onDropped; Subscription upstream; - Disposable timer; + DebounceEmitter timer; volatile long index; boolean done; - DebounceTimedSubscriber(Subscriber actual, long timeout, TimeUnit unit, Worker worker) { + DebounceTimedSubscriber(Subscriber actual, long timeout, TimeUnit unit, Worker worker, Consumer onDropped) { this.downstream = actual; this.timeout = timeout; this.unit = unit; this.worker = worker; + this.onDropped = onDropped; } @Override @@ -88,15 +93,26 @@ public void onNext(T t) { long idx = index + 1; index = idx; - Disposable d = timer; - if (d != null) { - d.dispose(); + DebounceEmitter currentEmitter = timer; + if (currentEmitter != null) { + currentEmitter.dispose(); + } + + if (onDropped != null && currentEmitter != null) { + try { + onDropped.accept(currentEmitter.value); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.cancel(); + done = true; + downstream.onError(ex); + worker.dispose(); + } } - DebounceEmitter de = new DebounceEmitter<>(t, idx, this); - timer = de; - d = worker.schedule(de, timeout, unit); - de.setResource(d); + DebounceEmitter newEmitter = new DebounceEmitter<>(t, idx, this); + timer = newEmitter; + newEmitter.setResource(worker.schedule(newEmitter, timeout, unit)); } @Override @@ -121,15 +137,13 @@ public void onComplete() { } done = true; - Disposable d = timer; + DebounceEmitter d = timer; if (d != null) { d.dispose(); } - @SuppressWarnings("unchecked") - DebounceEmitter de = (DebounceEmitter)d; - if (de != null) { - de.emit(); + if (d != null) { + d.emit(); } downstream.onComplete(); @@ -159,7 +173,7 @@ void emit(long idx, T t, DebounceEmitter emitter) { emitter.dispose(); } else { cancel(); - downstream.onError(new MissingBackpressureException("Could not deliver value due to lack of requests")); + downstream.onError(MissingBackpressureException.createDefault()); } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDefer.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDefer.java index 6c3d8f90082..b3ea3f1ecc5 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDefer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDefer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelay.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelay.java index e66acd39e9d..a7de73213ae 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelay.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelay.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -111,7 +111,9 @@ final class OnNext implements Runnable { @Override public void run() { - downstream.onNext(t); + if (!w.isDisposed()) { + downstream.onNext(t); + } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelaySubscriptionOther.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelaySubscriptionOther.java index c4e199c7e24..2f12cc6e4e7 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelaySubscriptionOther.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelaySubscriptionOther.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import java.util.concurrent.atomic.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDematerialize.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDematerialize.java index dc2de8e389c..10806f5776f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDematerialize.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDematerialize.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDetach.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDetach.java index e03ee6094b5..8d755b8ad36 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDetach.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDetach.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinct.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinct.java index bc624296114..7c3c777c269 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinct.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinct.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,10 +22,10 @@ import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.internal.subscribers.BasicFuseableSubscriber; import io.reactivex.rxjava3.internal.subscriptions.EmptySubscription; import io.reactivex.rxjava3.internal.util.ExceptionHelper; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class FlowableDistinct extends AbstractFlowableWithUpstream { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinctUntilChanged.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinctUntilChanged.java index 6eb323625d8..2c597556ec2 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinctUntilChanged.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinctUntilChanged.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,8 +18,8 @@ import io.reactivex.rxjava3.annotations.Nullable; import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscribers.*; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; public final class FlowableDistinctUntilChanged extends AbstractFlowableWithUpstream { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoAfterNext.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoAfterNext.java index 7aa451e1f6b..763e93a54a4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoAfterNext.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoAfterNext.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,8 +18,8 @@ import io.reactivex.rxjava3.annotations.Nullable; import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.functions.Consumer; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscribers.*; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; /** * Calls a consumer after pushing the current item to the downstream. diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoFinally.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoFinally.java index 9373819291d..71da8532274 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoFinally.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoFinally.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,8 +19,9 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Action; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.subscriptions.*; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnEach.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnEach.java index 2e6d45d5e73..3284a2e5075 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnEach.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnEach.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,9 +19,9 @@ import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscribers.*; import io.reactivex.rxjava3.internal.util.ExceptionHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class FlowableDoOnEach extends AbstractFlowableWithUpstream { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnLifecycle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnLifecycle.java index a75881d2ba0..8b56c38c705 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnLifecycle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnLifecycle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import org.reactivestreams.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAt.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAt.java index 91c9c0bee76..eecd3d1c174 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAt.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAt.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtMaybe.java index fc30483fd25..f62439c577f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtMaybePublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtMaybePublisher.java new file mode 100644 index 00000000000..b6b16a3e404 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtMaybePublisher.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import org.reactivestreams.Publisher; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.internal.operators.flowable.FlowableElementAtMaybe.ElementAtSubscriber; + +/** + * Emits the indexth element from a Publisher as a Maybe. + * + * @param the element type of the source + * @since 3.0.0 + */ +public final class FlowableElementAtMaybePublisher extends Maybe { + + final Publisher source; + + final long index; + + public FlowableElementAtMaybePublisher(Publisher source, long index) { + this.source = source; + this.index = index; + } + + @Override + protected void subscribeActual(MaybeObserver observer) { + source.subscribe(new ElementAtSubscriber<>(observer, index)); + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtSingle.java index b743b6a3b78..95b32bde6d1 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableEmpty.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableEmpty.java index 4a9bbe7d320..3606ac57d64 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableEmpty.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableEmpty.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,8 +16,8 @@ import org.reactivestreams.Subscriber; import io.reactivex.rxjava3.core.Flowable; -import io.reactivex.rxjava3.internal.fuseable.ScalarSupplier; import io.reactivex.rxjava3.internal.subscriptions.EmptySubscription; +import io.reactivex.rxjava3.operators.ScalarSupplier; /** * A source Flowable that signals an onSubscribe() + onComplete() only. diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableError.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableError.java index f65410ff116..190eb53c6be 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableError.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableError.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFilter.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFilter.java index 790881a1609..74a4413e36f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFilter.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFilter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,8 +18,9 @@ import io.reactivex.rxjava3.annotations.Nullable; import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.functions.Predicate; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.subscribers.*; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; +import io.reactivex.rxjava3.operators.QueueSubscription; public final class FlowableFilter extends AbstractFlowableWithUpstream { final Predicate predicate; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMap.java index ea6a4f76ed6..c250d3b1651 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,10 +22,9 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.*; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class FlowableFlatMap extends AbstractFlowableWithUpstream { @@ -150,14 +149,14 @@ public void onNext(T t) { if (u != null) { tryEmitScalar(u); } else { - if (maxConcurrency != Integer.MAX_VALUE && !cancelled - && ++scalarEmitted == scalarLimit) { + if (maxConcurrency != Integer.MAX_VALUE + && !cancelled && ++scalarEmitted == scalarLimit) { scalarEmitted = 0; upstream.request(scalarLimit); } } } else { - InnerSubscriber inner = new InnerSubscriber<>(this, uniqueId++); + InnerSubscriber inner = new InnerSubscriber<>(this, bufferSize, uniqueId++); if (addInner(inner)) { p.subscribe(inner); } @@ -234,8 +233,8 @@ void tryEmitScalar(U value) { if (r != Long.MAX_VALUE) { requested.decrementAndGet(); } - if (maxConcurrency != Integer.MAX_VALUE && !cancelled - && ++scalarEmitted == scalarLimit) { + if (maxConcurrency != Integer.MAX_VALUE + && !cancelled && ++scalarEmitted == scalarLimit) { scalarEmitted = 0; upstream.request(scalarLimit); } @@ -244,8 +243,7 @@ void tryEmitScalar(U value) { q = getMainQueue(); } if (!q.offer(value)) { - onError(new IllegalStateException("Scalar queue full?!")); - return; + onError(new QueueOverflowException()); } } if (decrementAndGet() == 0) { @@ -254,7 +252,7 @@ void tryEmitScalar(U value) { } else { SimpleQueue q = getMainQueue(); if (!q.offer(value)) { - onError(new IllegalStateException("Scalar queue full?!")); + onError(new QueueOverflowException()); return; } if (getAndIncrement() != 0) { @@ -264,15 +262,6 @@ void tryEmitScalar(U value) { drainLoop(); } - SimpleQueue getInnerQueue(InnerSubscriber inner) { - SimpleQueue q = inner.queue; - if (q == null) { - q = new SpscArrayQueue<>(bufferSize); - inner.queue = q; - } - return q; - } - void tryEmit(U value, InnerSubscriber inner) { if (get() == 0 && compareAndSet(0, 1)) { long r = requested.get(); @@ -285,11 +274,11 @@ void tryEmit(U value, InnerSubscriber inner) { inner.requestMore(1); } else { if (q == null) { - q = getInnerQueue(inner); + q = new SpscArrayQueue<>(bufferSize); + inner.queue = q; } if (!q.offer(value)) { - onError(new MissingBackpressureException("Inner queue full?!")); - return; + onError(new QueueOverflowException()); } } if (decrementAndGet() == 0) { @@ -302,7 +291,7 @@ void tryEmit(U value, InnerSubscriber inner) { inner.queue = q; } if (!q.offer(value)) { - onError(new MissingBackpressureException("Inner queue full?!")); + onError(new QueueOverflowException()); return; } if (getAndIncrement() != 0) { @@ -321,6 +310,11 @@ public void onError(Throwable t) { } if (errors.tryAddThrowableOrReport(t)) { done = true; + if (!delayErrors) { + for (InnerSubscriber a : subscribers.getAndSet(CANCELLED)) { + a.dispose(); + } + } drain(); } } @@ -379,35 +373,30 @@ void drainLoop() { long replenishMain = 0; if (svq != null) { - for (;;) { - long scalarEmission = 0; - U o = null; - while (r != 0L) { - o = svq.poll(); - - if (checkTerminate()) { - return; - } - if (o == null) { - break; - } + long scalarEmission = 0; + U o = null; + while (r != 0L) { + o = svq.poll(); - child.onNext(o); - - replenishMain++; - scalarEmission++; - r--; - } - if (scalarEmission != 0L) { - if (unbounded) { - r = Long.MAX_VALUE; - } else { - r = requested.addAndGet(-scalarEmission); - } + if (checkTerminate()) { + return; } - if (r == 0L || o == null) { + if (o == null) { break; } + + child.onNext(o); + + replenishMain++; + scalarEmission++; + r--; + } + if (scalarEmission != 0L) { + if (unbounded) { + r = Long.MAX_VALUE; + } else { + r = requested.addAndGet(-scalarEmission); + } } } @@ -457,15 +446,15 @@ void drainLoop() { U o = null; for (;;) { - if (checkTerminate()) { - return; - } SimpleQueue q = is.queue; if (q == null) { break; } long produced = 0; while (r != 0L) { + if (checkTerminate()) { + return; + } try { o = q.poll(); @@ -490,10 +479,6 @@ void drainLoop() { child.onNext(o); - if (checkTerminate()) { - return; - } - r--; produced++; } @@ -566,15 +551,12 @@ void clearScalarQueue() { } void disposeAll() { - InnerSubscriber[] a = subscribers.get(); + InnerSubscriber[] a = subscribers.getAndSet(CANCELLED); if (a != CANCELLED) { - a = subscribers.getAndSet(CANCELLED); - if (a != CANCELLED) { - for (InnerSubscriber inner : a) { - inner.dispose(); - } - errors.tryTerminateAndReport(); + for (InnerSubscriber inner : a) { + inner.dispose(); } + errors.tryTerminateAndReport(); } } @@ -606,10 +588,10 @@ static final class InnerSubscriber extends AtomicReference long produced; int fusionMode; - InnerSubscriber(MergeSubscriber parent, long id) { + InnerSubscriber(MergeSubscriber parent, int bufferSize, long id) { this.id = id; this.parent = parent; - this.bufferSize = parent.bufferSize; + this.bufferSize = bufferSize; this.limit = bufferSize >> 2; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapCompletable.java index 945e6a877ee..b69a6e2895f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -138,9 +138,7 @@ public void onError(Throwable e) { cancelled = true; upstream.cancel(); set.dispose(); - if (getAndSet(0) > 0) { - errors.tryTerminateConsumer(downstream); - } + errors.tryTerminateConsumer(downstream); } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapCompletableCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapCompletableCompletable.java index 00445c8018b..2d604e5157d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapCompletableCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapCompletableCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -146,9 +146,7 @@ public void onError(Throwable e) { disposed = true; upstream.cancel(); set.dispose(); - if (getAndSet(0) > 0) { - errors.tryTerminateConsumer(downstream); - } + errors.tryTerminateConsumer(downstream); } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapMaybe.java index 1036e73973f..2936fa9066d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,9 +23,9 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; /** * Maps upstream values into MaybeSources and merges their signals into one sequence. @@ -174,7 +174,7 @@ void innerSuccess(InnerObserver inner, R value) { SpscLinkedArrayQueue q = queue.get(); - if (d && (q == null || q.isEmpty())) { + if (checkTerminate(d, q)) { errors.tryTerminateConsumer(downstream); return; } @@ -205,16 +205,15 @@ void innerSuccess(InnerObserver inner, R value) { } SpscLinkedArrayQueue getOrCreateQueue() { - for (;;) { - SpscLinkedArrayQueue current = queue.get(); - if (current != null) { - return current; - } - current = new SpscLinkedArrayQueue<>(Flowable.bufferSize()); - if (queue.compareAndSet(null, current)) { - return current; - } + SpscLinkedArrayQueue current = queue.get(); + if (current != null) { + return current; } + current = new SpscLinkedArrayQueue<>(Flowable.bufferSize()); + if (queue.compareAndSet(null, current)) { + return current; + } + return queue.get(); } void innerError(InnerObserver inner, Throwable e) { @@ -240,7 +239,7 @@ void innerComplete(InnerObserver inner) { boolean d = active.decrementAndGet() == 0; SpscLinkedArrayQueue q = queue.get(); - if (d && (q == null || q.isEmpty())) { + if (checkTerminate(d, q)) { errors.tryTerminateConsumer(downstream); return; } @@ -261,6 +260,10 @@ void innerComplete(InnerObserver inner) { } } + static boolean checkTerminate(boolean d, SpscLinkedArrayQueue q) { + return d && (q == null || q.isEmpty()); + } + void drain() { if (getAndIncrement() == 0) { drainLoop(); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapMaybePublisher.java similarity index 53% rename from src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapPublisher.java rename to src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapMaybePublisher.java index 0f5be8917de..acc527215c4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapMaybePublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,31 +15,35 @@ import org.reactivestreams.*; -import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.internal.operators.flowable.FlowableFlatMapMaybe.FlatMapMaybeSubscriber; + +/** + * Maps upstream values into MaybeSources and merges their signals into one sequence. + * @param the source value type + * @param the result value type + */ +public final class FlowableFlatMapMaybePublisher extends Flowable { -public final class FlowableFlatMapPublisher extends Flowable { final Publisher source; - final Function> mapper; + + final Function> mapper; + final boolean delayErrors; + final int maxConcurrency; - final int bufferSize; - public FlowableFlatMapPublisher(Publisher source, - Function> mapper, - boolean delayErrors, int maxConcurrency, int bufferSize) { + public FlowableFlatMapMaybePublisher(Publisher source, Function> mapper, + boolean delayError, int maxConcurrency) { this.source = source; this.mapper = mapper; - this.delayErrors = delayErrors; + this.delayErrors = delayError; this.maxConcurrency = maxConcurrency; - this.bufferSize = bufferSize; } @Override - protected void subscribeActual(Subscriber s) { - if (FlowableScalarXMap.tryScalarXMapSubscribe(source, s, mapper)) { - return; - } - source.subscribe(FlowableFlatMap.subscribe(s, mapper, delayErrors, maxConcurrency, bufferSize)); + protected void subscribeActual(Subscriber s) { + source.subscribe(new FlatMapMaybeSubscriber<>(s, mapper, delayErrors, maxConcurrency)); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapSingle.java index d0c9002669a..f5277d603ab 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,9 +23,9 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; /** * Maps upstream values into SingleSources and merges their signals into one sequence. @@ -205,16 +205,15 @@ void innerSuccess(InnerObserver inner, R value) { } SpscLinkedArrayQueue getOrCreateQueue() { - for (;;) { - SpscLinkedArrayQueue current = queue.get(); - if (current != null) { - return current; - } - current = new SpscLinkedArrayQueue<>(Flowable.bufferSize()); - if (queue.compareAndSet(null, current)) { - return current; - } + SpscLinkedArrayQueue current = queue.get(); + if (current != null) { + return current; + } + current = new SpscLinkedArrayQueue<>(Flowable.bufferSize()); + if (queue.compareAndSet(null, current)) { + return current; } + return queue.get(); } void innerError(InnerObserver inner, Throwable e) { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapSinglePublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapSinglePublisher.java new file mode 100644 index 00000000000..570ef96f783 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapSinglePublisher.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import org.reactivestreams.*; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.internal.operators.flowable.FlowableFlatMapSingle.FlatMapSingleSubscriber; + +/** + * Maps upstream values into SingleSources and merges their signals into one sequence. + * @param the source value type + * @param the result value type + */ +public final class FlowableFlatMapSinglePublisher extends Flowable { + + final Publisher source; + + final Function> mapper; + + final boolean delayErrors; + + final int maxConcurrency; + + public FlowableFlatMapSinglePublisher(Publisher source, Function> mapper, + boolean delayError, int maxConcurrency) { + this.source = source; + this.mapper = mapper; + this.delayErrors = delayError; + this.maxConcurrency = maxConcurrency; + } + + @Override + protected void subscribeActual(Subscriber s) { + source.subscribe(new FlatMapSingleSubscriber<>(s, mapper, delayErrors, maxConcurrency)); + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlattenIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlattenIterable.java index 06f0b650e6c..0b9164e0cd6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlattenIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlattenIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,10 +22,11 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class FlowableFlattenIterable extends AbstractFlowableWithUpstream { @@ -179,7 +180,7 @@ public void onNext(T t) { return; } if (fusionMode == NONE && !queue.offer(t)) { - onError(new MissingBackpressureException("Queue is full?!")); + onError(new QueueOverflowException()); return; } drain(); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromAction.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromAction.java new file mode 100644 index 00000000000..693f40ddb41 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromAction.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import org.reactivestreams.Subscriber; + +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.fuseable.CancellableQueueFuseable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + +/** + * Executes an {@link Action} and signals its exception or completes normally. + * + * @param the value type + * @since 3.0.0 + */ +public final class FlowableFromAction extends Flowable implements Supplier { + + final Action action; + + public FlowableFromAction(Action action) { + this.action = action; + } + + @Override + protected void subscribeActual(Subscriber subscriber) { + CancellableQueueFuseable qs = new CancellableQueueFuseable<>(); + subscriber.onSubscribe(qs); + + if (!qs.isDisposed()) { + + try { + action.run(); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + if (!qs.isDisposed()) { + subscriber.onError(ex); + } else { + RxJavaPlugins.onError(ex); + } + return; + } + + if (!qs.isDisposed()) { + subscriber.onComplete(); + } + } + } + + @Override + public T get() throws Throwable { + action.run(); + return null; // considered as onComplete() + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromArray.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromArray.java index 9b9a4c66f4f..1b13bcff3bb 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromArray.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromArray.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,9 +17,9 @@ import io.reactivex.rxjava3.annotations.Nullable; import io.reactivex.rxjava3.core.Flowable; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; import java.util.Objects; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCallable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCallable.java index 603f09abaee..e2a331d2f0c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCallable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCallable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCompletable.java new file mode 100644 index 00000000000..c4b15b947db --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCompletable.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import org.reactivestreams.Subscriber; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.internal.disposables.DisposableHelper; +import io.reactivex.rxjava3.internal.fuseable.*; + +/** + * Wrap a Completable into a Flowable. + * + * @param the value type + * @since 3.0.0 + */ +public final class FlowableFromCompletable extends Flowable implements HasUpstreamCompletableSource { + + final CompletableSource source; + + public FlowableFromCompletable(CompletableSource source) { + this.source = source; + } + + @Override + public CompletableSource source() { + return source; + } + + @Override + protected void subscribeActual(Subscriber observer) { + source.subscribe(new FromCompletableObserver(observer)); + } + + public static final class FromCompletableObserver + extends AbstractEmptyQueueFuseable + implements CompletableObserver { + + final Subscriber downstream; + + Disposable upstream; + + public FromCompletableObserver(Subscriber downstream) { + this.downstream = downstream; + } + + @Override + public void cancel() { + upstream.dispose(); + upstream = DisposableHelper.DISPOSED; + } + + @Override + public void onSubscribe(Disposable d) { + if (DisposableHelper.validate(this.upstream, d)) { + this.upstream = d; + + downstream.onSubscribe(this); + } + } + + @Override + public void onComplete() { + upstream = DisposableHelper.DISPOSED; + downstream.onComplete(); + } + + @Override + public void onError(Throwable e) { + upstream = DisposableHelper.DISPOSED; + downstream.onError(e); + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromFuture.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromFuture.java index 57dc02774fe..0fef3682875 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromFuture.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromFuture.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromIterable.java index 7ae3f3e7d1e..314f0f2f54a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,9 +21,9 @@ import io.reactivex.rxjava3.annotations.Nullable; import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.exceptions.Exceptions; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; public final class FlowableFromIterable extends Flowable { @@ -73,14 +73,14 @@ public static void subscribe(Subscriber s, Iterator abstract static class BaseRangeSubscription extends BasicQueueSubscription { private static final long serialVersionUID = -2252972430506210021L; - Iterator it; + Iterator iterator; volatile boolean cancelled; boolean once; BaseRangeSubscription(Iterator it) { - this.it = it; + this.iterator = it; } @Override @@ -91,27 +91,34 @@ public final int requestFusion(int mode) { @Nullable @Override public final T poll() { - if (it == null) { + if (iterator == null) { return null; } if (!once) { once = true; } else { - if (!it.hasNext()) { + if (!iterator.hasNext()) { return null; } } - return Objects.requireNonNull(it.next(), "Iterator.next() returned a null value"); + return Objects.requireNonNull(iterator.next(), "Iterator.next() returned a null value"); } @Override public final boolean isEmpty() { - return it == null || !it.hasNext(); + Iterator it = this.iterator; + if (it != null) { + if (!once || it.hasNext()) { + return false; + } + clear(); + } + return true; } @Override public final void clear() { - it = null; + iterator = null; } @Override @@ -150,7 +157,7 @@ static final class IteratorSubscription extends BaseRangeSubscription { @Override void fastPath() { - Iterator it = this.it; + Iterator it = this.iterator; Subscriber a = downstream; for (;;) { if (cancelled) { @@ -204,7 +211,7 @@ void fastPath() { @Override void slowPath(long r) { long e = 0L; - Iterator it = this.it; + Iterator it = this.iterator; Subscriber a = downstream; for (;;) { @@ -286,7 +293,7 @@ static final class IteratorConditionalSubscription extends BaseRangeSubscript @Override void fastPath() { - Iterator it = this.it; + Iterator it = this.iterator; ConditionalSubscriber a = downstream; for (;;) { if (cancelled) { @@ -340,7 +347,7 @@ void fastPath() { @Override void slowPath(long r) { long e = 0L; - Iterator it = this.it; + Iterator it = this.iterator; ConditionalSubscriber a = downstream; for (;;) { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservable.java index 105c6b6ee2d..664dbf4acf3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import org.reactivestreams.*; @@ -18,9 +19,10 @@ import io.reactivex.rxjava3.disposables.Disposable; public final class FlowableFromObservable extends Flowable { - private final Observable upstream; - public FlowableFromObservable(Observable upstream) { + private final ObservableSource upstream; + + public FlowableFromObservable(ObservableSource upstream) { this.upstream = upstream; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromPublisher.java index df575a0274f..a021846388f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromRunnable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromRunnable.java new file mode 100644 index 00000000000..0d503d46684 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromRunnable.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import org.reactivestreams.Subscriber; + +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.Supplier; +import io.reactivex.rxjava3.internal.fuseable.CancellableQueueFuseable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + +/** + * Executes an {@link Runnable} and signals its exception or completes normally. + * + * @param the value type + * @since 3.0.0 + */ +public final class FlowableFromRunnable extends Flowable implements Supplier { + + final Runnable run; + + public FlowableFromRunnable(Runnable run) { + this.run = run; + } + + @Override + protected void subscribeActual(Subscriber subscriber) { + CancellableQueueFuseable qs = new CancellableQueueFuseable<>(); + subscriber.onSubscribe(qs); + + if (!qs.isDisposed()) { + + try { + run.run(); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + if (!qs.isDisposed()) { + subscriber.onError(ex); + } else { + RxJavaPlugins.onError(ex); + } + return; + } + + if (!qs.isDisposed()) { + subscriber.onComplete(); + } + } + } + + @Override + public T get() throws Throwable { + run.run(); + return null; // considered as onComplete() + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSupplier.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSupplier.java index 84fbae7eec0..ca2a331396c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSupplier.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSupplier.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGenerate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGenerate.java index 2feda7ad97e..3639d64eeba 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGenerate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGenerate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupBy.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupBy.java index 3cb84d4d6b5..50e641ffc1c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupBy.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupBy.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,9 +24,9 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.flowables.GroupedFlowable; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class FlowableGroupBy extends AbstractFlowableWithUpstream> { @@ -168,7 +168,7 @@ public void onNext(T t) { if (emittedGroups != get()) { downstream.onNext(group); } else { - MissingBackpressureException mbe = new MissingBackpressureException(groupHangWarning(emittedGroups)); + MissingBackpressureException mbe = groupHangWarning(emittedGroups); mbe.initCause(ex); onError(mbe); return; @@ -194,13 +194,13 @@ public void onNext(T t) { } } else { upstream.cancel(); - onError(new MissingBackpressureException(groupHangWarning(emittedGroups))); + onError(groupHangWarning(emittedGroups)); } } } - static String groupHangWarning(long n) { - return "Unable to emit a new group (#" + n + ") due to lack of requests. Please make sure the downstream can always accept a new group as well as each group is consumed in order for the whole operator to be able to proceed."; + static MissingBackpressureException groupHangWarning(long n) { + return new MissingBackpressureException("Unable to emit a new group (#" + n + ") due to lack of requests. Please make sure the downstream can always accept a new group as well as each group is consumed in order for the whole operator to be able to proceed."); } @Override @@ -214,9 +214,7 @@ public void onError(Throwable t) { g.onError(t); } groups.clear(); - if (evictedGroups != null) { - evictedGroups.clear(); - } + completeEvictions(); downstream.onError(t); } @@ -226,10 +224,10 @@ public void onComplete() { for (GroupedUnicast g : groups.values()) { g.onComplete(); } + groups.clear(); - if (evictedGroups != null) { - evictedGroups.clear(); - } + completeEvictions(); + done = true; downstream.onComplete(); } @@ -259,8 +257,9 @@ private void completeEvictions() { int count = 0; GroupedUnicast evictedGroup; while ((evictedGroup = evictedGroups.poll()) != null) { - evictedGroup.onComplete(); - count++; + if (evictedGroup.state.tryComplete()) { + count++; + } } if (count != 0) { groupCount.addAndGet(-count); @@ -270,9 +269,10 @@ private void completeEvictions() { public void cancel(K key) { Object mapKey = key != null ? key : NULL_KEY; - groups.remove(mapKey); - if (groupCount.decrementAndGet() == 0) { - upstream.cancel(); + if (groups.remove(mapKey) != null) { + if (groupCount.decrementAndGet() == 0) { + upstream.cancel(); + } } } @@ -382,6 +382,8 @@ static final class State extends BasicIntQueueSubscription implements P static final int ABANDONED = 2; static final int ABANDONED_HAS_SUBSCRIBER = ABANDONED | HAS_SUBSCRIBER; + final AtomicBoolean evictOnce = new AtomicBoolean(); + State(int bufferSize, GroupBySubscriber parent, K key, boolean delayError) { this.queue = new SpscLinkedArrayQueue<>(bufferSize); this.parent = parent; @@ -401,6 +403,7 @@ public void request(long n) { public void cancel() { if (cancelled.compareAndSet(false, true)) { cancelParent(); + drain(); } } @@ -442,9 +445,18 @@ public void onComplete() { drain(); } + boolean tryComplete() { + boolean canEvict = evictOnce.compareAndSet(false, true); + done = true; + drain(); + return canEvict; + } + void cancelParent() { if ((once.get() & ABANDONED) == 0) { - parent.cancel(key); + if (evictOnce.compareAndSet(false, true)) { + parent.cancel(key); + } } } @@ -516,37 +528,44 @@ void drainNormal() { final SpscLinkedArrayQueue q = queue; final boolean delayError = this.delayError; Subscriber a = actual.get(); + final AtomicBoolean cancelled = this.cancelled; + + outer: for (;;) { - if (a != null) { - long r = requested.get(); - long e = 0; + if (cancelled.get()) { + cleanupQueue(0, false); + } else { + if (a != null) { + long r = requested.get(); + long e = 0; - while (e != r) { - boolean d = done; - T v = q.poll(); - boolean empty = v == null; + while (e != r) { + boolean d = done; + T v = q.poll(); + boolean empty = v == null; - if (checkTerminated(d, empty, a, delayError, e)) { - return; - } + if (checkTerminated(d, empty, a, delayError, e, !empty)) { + continue outer; + } - if (empty) { - break; - } + if (empty) { + break; + } - a.onNext(v); + a.onNext(v); - e++; - } + e++; + } - if (e == r && checkTerminated(done, q.isEmpty(), a, delayError, e)) { - return; - } + if (e == r && checkTerminated(done, q.isEmpty(), a, delayError, e, false)) { + continue outer; + } - if (e != 0L) { - BackpressureHelper.produced(requested, e); - // replenish based on this batch run - requestParent(e); + if (e != 0L) { + BackpressureHelper.produced(requested, e); + // replenish based on this batch run + requestParent(e); + } } } @@ -566,28 +585,45 @@ void requestParent(long e) { } } - boolean checkTerminated(boolean d, boolean empty, Subscriber a, boolean delayError, long emitted) { + void cleanupQueue(long emitted, boolean polled) { + // if this group is canceled, all accumulated emissions and + // remaining items in the queue should be requested + // so that other groups can proceed + while (queue.poll() != null) { + emitted++; + } + + replenishParent(emitted, polled); + } + + void replenishParent(long emitted, boolean polled) { + if (polled) { + emitted++; + } + if (emitted != 0L) { + requestParent(emitted); + } + } + + boolean checkTerminated(boolean d, boolean empty, Subscriber a, + boolean delayError, long emitted, boolean polled) { if (cancelled.get()) { - // if this group is canceled, all accumulated emissions and - // remaining items in the queue should be requested - // so that other groups can proceed - while (queue.poll() != null) { - emitted++; - } - if (emitted != 0L) { - requestParent(emitted); - } + cleanupQueue(emitted, polled); return true; } if (d) { if (delayError) { if (empty) { + cancelled.lazySet(true); Throwable e = error; if (e != null) { a.onError(e); } else { a.onComplete(); + // completion doesn't mean the parent has completed + // because of evicted groups + replenishParent(emitted, polled); } return true; } @@ -595,11 +631,17 @@ boolean checkTerminated(boolean d, boolean empty, Subscriber a, boole Throwable e = error; if (e != null) { queue.clear(); + cancelled.lazySet(true); a.onError(e); return true; } else if (empty) { + cancelled.lazySet(true); a.onComplete(); + + // completion doesn't mean the parent has completed + // because of evicted groups + replenishParent(emitted, polled); return true; } } @@ -610,10 +652,13 @@ boolean checkTerminated(boolean d, boolean empty, Subscriber a, boole @Override public int requestFusion(int mode) { + // FIXME fusion mode causes hangs + /* if ((mode & ASYNC) != 0) { outputFused = true; return ASYNC; } + */ return NONE; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupJoin.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupJoin.java index a950de7a96f..c9619c48b70 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupJoin.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupJoin.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.operators.flowable; @@ -25,10 +22,10 @@ import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.SimpleQueue; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.UnicastProcessor; @@ -279,7 +276,7 @@ void drain() { a.onNext(w); BackpressureHelper.produced(requested, 1); } else { - fail(new MissingBackpressureException("Could not emit value due to lack of requests"), a, q); + fail(MissingBackpressureException.createDefault(), a, q); return; } @@ -330,7 +327,7 @@ else if (mode == LEFT_CLOSE) { up.onComplete(); } } - else if (mode == RIGHT_CLOSE) { + else { LeftRightEndSubscriber end = (LeftRightEndSubscriber)val; rights.remove(end.index); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableHide.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableHide.java index 17d84f178a1..bc9b47011b6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableHide.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableHide.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIgnoreElements.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIgnoreElements.java index 9afee2e50d0..20f546feee8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIgnoreElements.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIgnoreElements.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,8 +17,8 @@ import io.reactivex.rxjava3.annotations.Nullable; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.internal.fuseable.QueueSubscription; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.operators.QueueSubscription; public final class FlowableIgnoreElements extends AbstractFlowableWithUpstream { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIgnoreElementsCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIgnoreElementsCompletable.java index 4eaced342e5..19d8546d2df 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIgnoreElementsCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIgnoreElementsCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableInternalHelper.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableInternalHelper.java index 41dc08d9202..781d4758724 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableInternalHelper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableInternalHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import java.util.Objects; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableInterval.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableInterval.java index 9ef04ea11c0..98fbe6dee16 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableInterval.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableInterval.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -93,7 +93,7 @@ public void run() { downstream.onNext(count++); BackpressureHelper.produced(this, 1); } else { - downstream.onError(new MissingBackpressureException("Can't deliver value " + count + " due to lack of requests")); + downstream.onError(new MissingBackpressureException("Could not emit value " + count + " due to lack of requests")); DisposableHelper.dispose(resource); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIntervalRange.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIntervalRange.java index e9580f40c61..cfa605882df 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIntervalRange.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIntervalRange.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -114,7 +114,7 @@ public void run() { decrementAndGet(); } } else { - downstream.onError(new MissingBackpressureException("Can't deliver value " + count + " due to lack of requests")); + downstream.onError(new MissingBackpressureException("Could not emit value " + count + " due to lack of requests")); DisposableHelper.dispose(resource); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableJoin.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableJoin.java index 01cf71023f2..9cda3d457db 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableJoin.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableJoin.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,11 +22,11 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.SimpleQueue; import io.reactivex.rxjava3.internal.operators.flowable.FlowableGroupJoin.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class FlowableJoin extends AbstractFlowableWithUpstream { @@ -260,7 +260,7 @@ void drain() { e++; } else { - ExceptionHelper.addThrowable(error, new MissingBackpressureException("Could not emit value due to lack of requests")); + ExceptionHelper.addThrowable(error, MissingBackpressureException.createDefault()); q.clear(); cancelAll(); errorAll(a); @@ -321,7 +321,7 @@ else if (mode == RIGHT_VALUE) { e++; } else { - ExceptionHelper.addThrowable(error, new MissingBackpressureException("Could not emit value due to lack of requests")); + ExceptionHelper.addThrowable(error, MissingBackpressureException.createDefault()); q.clear(); cancelAll(); errorAll(a); @@ -339,7 +339,7 @@ else if (mode == LEFT_CLOSE) { lefts.remove(end.index); disposables.remove(end); } - else if (mode == RIGHT_CLOSE) { + else { LeftRightEndSubscriber end = (LeftRightEndSubscriber)val; rights.remove(end.index); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableJust.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableJust.java index d17c9644faf..2926d49509c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableJust.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableJust.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,8 +16,8 @@ import org.reactivestreams.Subscriber; import io.reactivex.rxjava3.core.Flowable; -import io.reactivex.rxjava3.internal.fuseable.ScalarSupplier; import io.reactivex.rxjava3.internal.subscriptions.ScalarSubscription; +import io.reactivex.rxjava3.operators.ScalarSupplier; /** * Represents a constant scalar value. diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLastMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLastMaybe.java index 936e68c2112..056dfe92018 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLastMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLastMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLastSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLastSingle.java index 70346f3555c..ef4fb1a0156 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLastSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLastSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLift.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLift.java index 5f92e95652f..99e4075bc4d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLift.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLift.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMap.java index 208baca0b25..90ad6c2883a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,8 +18,8 @@ import io.reactivex.rxjava3.annotations.Nullable; import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscribers.*; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; import java.util.Objects; @@ -115,7 +115,12 @@ public void onNext(T t) { @Override public boolean tryOnNext(T t) { if (done) { - return false; + return true; + } + + if (sourceMode != NONE) { + downstream.tryOnNext(null); + return true; } U v; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapNotification.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapNotification.java index b01d6dc5a07..be2d78062e7 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapNotification.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapNotification.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapPublisher.java index 159efcea6c1..cc8ccb8fe82 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMaterialize.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMaterialize.java index 2b361427b18..7a806b8d5df 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMaterialize.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMaterialize.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithCompletable.java index a0725a1d647..ccd48a78fad 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithMaybe.java index 7d3be91bea5..e7581bcaed4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,10 +20,10 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimplePlainQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; /** * Merges an Observable and a Maybe by emitting the items of the Observable and the success diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithSingle.java index 997ad3fa2e9..b0f3e8b3eda 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,10 +20,10 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimplePlainQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; /** * Merges an Observable and a Maybe by emitting the items of the Observable and the success diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableNever.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableNever.java index 9dc0611920a..83aeb1533d4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableNever.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableNever.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import org.reactivestreams.Subscriber; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn.java index 3a4f237e5bb..576debbf2b7 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,10 +21,12 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Scheduler.Worker; import io.reactivex.rxjava3.exceptions.*; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class FlowableObserveOn extends AbstractFlowableWithUpstream { @@ -111,7 +113,7 @@ public final void onNext(T t) { if (!queue.offer(t)) { upstream.cancel(); - error = new MissingBackpressureException("Queue is full?!"); + error = new QueueOverflowException(); done = true; } trySchedule(); @@ -242,8 +244,7 @@ public final boolean isEmpty() { } } - static final class ObserveOnSubscriber extends BaseObserveOnSubscriber - implements FlowableSubscriber { + static final class ObserveOnSubscriber extends BaseObserveOnSubscriber { private static final long serialVersionUID = -4547113800637756442L; @@ -350,15 +351,10 @@ void runSync() { return; } - int w = get(); - if (missed == w) { - produced = e; - missed = addAndGet(-missed); - if (missed == 0) { - break; - } - } else { - missed = w; + produced = e; + missed = addAndGet(-missed); + if (missed == 0) { + break; } } } @@ -593,15 +589,10 @@ void runSync() { return; } - int w = get(); - if (missed == w) { - produced = e; - missed = addAndGet(-missed); - if (missed == 0) { - break; - } - } else { - missed = w; + produced = e; + missed = addAndGet(-missed); + if (missed == 0) { + break; } } } @@ -662,16 +653,11 @@ void runAsync() { return; } - int w = get(); - if (missed == w) { - produced = emitted; - consumed = polled; - missed = addAndGet(-missed); - if (missed == 0) { - break; - } - } else { - missed = w; + produced = emitted; + consumed = polled; + missed = addAndGet(-missed); + if (missed == 0) { + break; } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBuffer.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBuffer.java index 19d28291ba0..db58b68a103 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBuffer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBuffer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,30 +20,31 @@ import io.reactivex.rxjava3.annotations.Nullable; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; -import io.reactivex.rxjava3.functions.Action; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; -import io.reactivex.rxjava3.internal.queue.*; +import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.operators.*; public final class FlowableOnBackpressureBuffer extends AbstractFlowableWithUpstream { final int bufferSize; final boolean unbounded; final boolean delayError; final Action onOverflow; + final Consumer onDropped; public FlowableOnBackpressureBuffer(Flowable source, int bufferSize, boolean unbounded, - boolean delayError, Action onOverflow) { + boolean delayError, Action onOverflow, Consumer onDropped) { super(source); this.bufferSize = bufferSize; this.unbounded = unbounded; this.delayError = delayError; this.onOverflow = onOverflow; + this.onDropped = onDropped; } @Override protected void subscribeActual(Subscriber s) { - source.subscribe(new BackpressureBufferSubscriber<>(s, bufferSize, unbounded, delayError, onOverflow)); + source.subscribe(new BackpressureBufferSubscriber<>(s, bufferSize, unbounded, delayError, onOverflow, onDropped)); } static final class BackpressureBufferSubscriber extends BasicIntQueueSubscription implements FlowableSubscriber { @@ -54,6 +55,7 @@ static final class BackpressureBufferSubscriber extends BasicIntQueueSubscrip final SimplePlainQueue queue; final boolean delayError; final Action onOverflow; + final Consumer onDropped; Subscription upstream; @@ -67,10 +69,11 @@ static final class BackpressureBufferSubscriber extends BasicIntQueueSubscrip boolean outputFused; BackpressureBufferSubscriber(Subscriber actual, int bufferSize, - boolean unbounded, boolean delayError, Action onOverflow) { + boolean unbounded, boolean delayError, Action onOverflow, Consumer onDropped) { this.downstream = actual; this.onOverflow = onOverflow; this.delayError = delayError; + this.onDropped = onDropped; SimplePlainQueue q; @@ -99,6 +102,7 @@ public void onNext(T t) { MissingBackpressureException ex = new MissingBackpressureException("Buffer is full"); try { onOverflow.run(); + onDropped.accept(t); } catch (Throwable e) { Exceptions.throwIfFatal(e); ex.initCause(e); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBufferStrategy.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBufferStrategy.java index 6e458356b66..7963fb7d409 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBufferStrategy.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBufferStrategy.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,7 +20,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; -import io.reactivex.rxjava3.functions.Action; +import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.BackpressureHelper; import io.reactivex.rxjava3.plugins.RxJavaPlugins; @@ -38,17 +38,21 @@ public final class FlowableOnBackpressureBufferStrategy extends AbstractFlowa final BackpressureOverflowStrategy strategy; + final Consumer onDropped; + public FlowableOnBackpressureBufferStrategy(Flowable source, - long bufferSize, Action onOverflow, BackpressureOverflowStrategy strategy) { + long bufferSize, Action onOverflow, BackpressureOverflowStrategy strategy, + Consumer onDropped) { super(source); this.bufferSize = bufferSize; this.onOverflow = onOverflow; this.strategy = strategy; + this.onDropped = onDropped; } @Override protected void subscribeActual(Subscriber s) { - source.subscribe(new OnBackpressureBufferStrategySubscriber<>(s, onOverflow, strategy, bufferSize)); + source.subscribe(new OnBackpressureBufferStrategySubscriber<>(s, onOverflow, strategy, bufferSize, onDropped)); } static final class OnBackpressureBufferStrategySubscriber @@ -61,6 +65,8 @@ static final class OnBackpressureBufferStrategySubscriber final Action onOverflow; + final Consumer onDropped; + final BackpressureOverflowStrategy strategy; final long bufferSize; @@ -77,13 +83,15 @@ static final class OnBackpressureBufferStrategySubscriber Throwable error; OnBackpressureBufferStrategySubscriber(Subscriber actual, Action onOverflow, - BackpressureOverflowStrategy strategy, long bufferSize) { + BackpressureOverflowStrategy strategy, long bufferSize, + Consumer onDropped) { this.downstream = actual; this.onOverflow = onOverflow; this.strategy = strategy; this.bufferSize = bufferSize; this.requested = new AtomicLong(); this.deque = new ArrayDeque<>(); + this.onDropped = onDropped; } @Override @@ -104,44 +112,60 @@ public void onNext(T t) { } boolean callOnOverflow = false; boolean callError = false; + boolean callDrain = false; Deque dq = deque; + T toDrop = null; synchronized (dq) { if (dq.size() == bufferSize) { switch (strategy) { case DROP_LATEST: - dq.pollLast(); + toDrop = dq.pollLast(); dq.offer(t); callOnOverflow = true; break; case DROP_OLDEST: - dq.poll(); + toDrop = dq.poll(); dq.offer(t); callOnOverflow = true; break; default: // signal error + toDrop = t; callError = true; break; } } else { dq.offer(t); + callDrain = true; } } - if (callOnOverflow) { - if (onOverflow != null) { - try { - onOverflow.run(); - } catch (Throwable ex) { - Exceptions.throwIfFatal(ex); - upstream.cancel(); - onError(ex); - } + if (callOnOverflow && onOverflow != null) { + try { + onOverflow.run(); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.cancel(); + onError(ex); } - } else if (callError) { + } + + if (onDropped != null && toDrop != null) { + try { + onDropped.accept(toDrop); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.cancel(); + onError(ex); + } + } + + if (callError) { upstream.cancel(); - onError(new MissingBackpressureException()); - } else { + onError(MissingBackpressureException.createDefault()); + } + + if (callDrain) { drain(); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureDrop.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureDrop.java index 0db3cd3cc25..799c5dbca19 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureDrop.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureDrop.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureError.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureError.java index b85e1281fb2..acaf165069f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureError.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureError.java @@ -1,11 +1,11 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. - *

+ * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at - *

+ * * http://www.apache.org/licenses/LICENSE-2.0 - *

+ * * Unless required by applicable law or agreed to in writing, software distributed under the License is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. @@ -65,7 +65,8 @@ public void onNext(T t) { downstream.onNext(t); BackpressureHelper.produced(this, 1); } else { - onError(new MissingBackpressureException("could not emit value due to lack of requests")); + upstream.cancel(); + onError(MissingBackpressureException.createDefault()); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureLatest.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureLatest.java index 6123475ef00..155e284e93a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureLatest.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureLatest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,159 +13,50 @@ package io.reactivex.rxjava3.internal.operators.flowable; -import java.util.concurrent.atomic.*; - -import org.reactivestreams.*; - -import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; -import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.Consumer; +import org.reactivestreams.Subscriber; public final class FlowableOnBackpressureLatest extends AbstractFlowableWithUpstream { - public FlowableOnBackpressureLatest(Flowable source) { + final Consumer onDropped; + + public FlowableOnBackpressureLatest(Flowable source, Consumer onDropped) { super(source); + this.onDropped = onDropped; } @Override protected void subscribeActual(Subscriber s) { - source.subscribe(new BackpressureLatestSubscriber<>(s)); + source.subscribe(new BackpressureLatestSubscriber<>(s, onDropped)); } - static final class BackpressureLatestSubscriber extends AtomicInteger implements FlowableSubscriber, Subscription { + static final class BackpressureLatestSubscriber extends AbstractBackpressureThrottlingSubscriber { private static final long serialVersionUID = 163080509307634843L; - final Subscriber downstream; - - Subscription upstream; - - volatile boolean done; - Throwable error; - - volatile boolean cancelled; - - final AtomicLong requested = new AtomicLong(); + final Consumer onDropped; - final AtomicReference current = new AtomicReference<>(); - - BackpressureLatestSubscriber(Subscriber downstream) { - this.downstream = downstream; - } - - @Override - public void onSubscribe(Subscription s) { - if (SubscriptionHelper.validate(this.upstream, s)) { - this.upstream = s; - downstream.onSubscribe(this); - s.request(Long.MAX_VALUE); - } + BackpressureLatestSubscriber(Subscriber downstream, + Consumer onDropped) { + super(downstream); + this.onDropped = onDropped; } @Override public void onNext(T t) { - current.lazySet(t); - drain(); - } - - @Override - public void onError(Throwable t) { - error = t; - done = true; - drain(); - } - - @Override - public void onComplete() { - done = true; - drain(); - } - - @Override - public void request(long n) { - if (SubscriptionHelper.validate(n)) { - BackpressureHelper.add(requested, n); - drain(); - } - } - - @Override - public void cancel() { - if (!cancelled) { - cancelled = true; - upstream.cancel(); - - if (getAndIncrement() == 0) { - current.lazySet(null); + T oldValue = current.getAndSet(t); + if (onDropped != null && oldValue != null) { + try { + onDropped.accept(oldValue); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.cancel(); + downstream.onError(ex); } } - } - - void drain() { - if (getAndIncrement() != 0) { - return; - } - final Subscriber a = downstream; - int missed = 1; - final AtomicLong r = requested; - final AtomicReference q = current; - - for (;;) { - long e = 0L; - - while (e != r.get()) { - boolean d = done; - T v = q.getAndSet(null); - boolean empty = v == null; - - if (checkTerminated(d, empty, a, q)) { - return; - } - - if (empty) { - break; - } - - a.onNext(v); - - e++; - } - - if (e == r.get() && checkTerminated(done, q.get() == null, a, q)) { - return; - } - - if (e != 0L) { - BackpressureHelper.produced(r, e); - } - - missed = addAndGet(-missed); - if (missed == 0) { - break; - } - } - } - - boolean checkTerminated(boolean d, boolean empty, Subscriber a, AtomicReference q) { - if (cancelled) { - q.lazySet(null); - return true; - } - - if (d) { - Throwable e = error; - if (e != null) { - q.lazySet(null); - a.onError(e); - return true; - } else - if (empty) { - a.onComplete(); - return true; - } - } - - return false; + drain(); } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureReduce.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureReduce.java new file mode 100644 index 00000000000..9a6abab89ca --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureReduce.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.BiFunction; +import org.reactivestreams.Subscriber; + +import java.util.Objects; + +public final class FlowableOnBackpressureReduce extends AbstractFlowableWithUpstream { + + final BiFunction reducer; + + public FlowableOnBackpressureReduce(@NonNull Flowable source, @NonNull BiFunction reducer) { + super(source); + this.reducer = reducer; + } + + @Override + protected void subscribeActual(@NonNull Subscriber s) { + source.subscribe(new BackpressureReduceSubscriber<>(s, reducer)); + } + + static final class BackpressureReduceSubscriber extends AbstractBackpressureThrottlingSubscriber { + + private static final long serialVersionUID = 821363947659780367L; + + final BiFunction reducer; + + BackpressureReduceSubscriber(@NonNull Subscriber downstream, @NonNull BiFunction reducer) { + super(downstream); + this.reducer = reducer; + } + + @Override + public void onNext(T t) { + T v = current.get(); + if (v != null) { + v = current.getAndSet(null); + } + if (v == null) { + current.lazySet(t); + } else { + try { + current.lazySet(Objects.requireNonNull(reducer.apply(v, t), "The reducer returned a null value")); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.cancel(); + onError(ex); + return; + } + } + drain(); + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureReduceWith.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureReduceWith.java new file mode 100644 index 00000000000..faed7232406 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureReduceWith.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.BiFunction; +import io.reactivex.rxjava3.functions.Supplier; +import org.reactivestreams.Subscriber; + +import java.util.Objects; + +public final class FlowableOnBackpressureReduceWith extends AbstractFlowableWithUpstream { + + final BiFunction reducer; + final Supplier supplier; + + public FlowableOnBackpressureReduceWith(@NonNull Flowable source, + @NonNull Supplier supplier, + @NonNull BiFunction reducer) { + super(source); + this.reducer = reducer; + this.supplier = supplier; + } + + @Override + protected void subscribeActual(@NonNull Subscriber s) { + source.subscribe(new BackpressureReduceWithSubscriber<>(s, supplier, reducer)); + } + + static final class BackpressureReduceWithSubscriber extends AbstractBackpressureThrottlingSubscriber { + + private static final long serialVersionUID = 8255923705960622424L; + + final BiFunction reducer; + final Supplier supplier; + + BackpressureReduceWithSubscriber(@NonNull Subscriber downstream, + @NonNull Supplier supplier, + @NonNull BiFunction reducer) { + super(downstream); + this.reducer = reducer; + this.supplier = supplier; + } + + @Override + public void onNext(T t) { + R v = current.get(); + if (v != null) { + v = current.getAndSet(null); + } + try { + if (v == null) { + current.lazySet(Objects.requireNonNull( + reducer.apply(Objects.requireNonNull(supplier.get(), "The supplier returned a null value"), t), + "The reducer returned a null value" + )); + } else { + current.lazySet(Objects.requireNonNull(reducer.apply(v, t), "The reducer returned a null value")); + } + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.cancel(); + onError(ex); + return; + } + drain(); + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorComplete.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorComplete.java new file mode 100644 index 00000000000..a0999f25c43 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorComplete.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import org.reactivestreams.*; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.functions.Predicate; +import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; + +/** + * Emits an onComplete if the source emits an onError and the predicate returns true for + * that Throwable. + * + * @param the value type + * @since 3.0.0 + */ +public final class FlowableOnErrorComplete extends AbstractFlowableWithUpstream { + + final Predicate predicate; + + public FlowableOnErrorComplete(Flowable source, + Predicate predicate) { + super(source); + this.predicate = predicate; + } + + @Override + protected void subscribeActual(Subscriber observer) { + source.subscribe(new OnErrorCompleteSubscriber<>(observer, predicate)); + } + + public static final class OnErrorCompleteSubscriber + implements FlowableSubscriber, Subscription { + + final Subscriber downstream; + + final Predicate predicate; + + Subscription upstream; + + public OnErrorCompleteSubscriber(Subscriber actual, Predicate predicate) { + this.downstream = actual; + this.predicate = predicate; + } + + @Override + public void onSubscribe(Subscription s) { + if (SubscriptionHelper.validate(this.upstream, s)) { + this.upstream = s; + + downstream.onSubscribe(this); + } + } + + @Override + public void onNext(T value) { + downstream.onNext(value); + } + + @Override + public void onError(Throwable e) { + boolean b; + + try { + b = predicate.test(e); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + downstream.onError(new CompositeException(e, ex)); + return; + } + + if (b) { + downstream.onComplete(); + } else { + downstream.onError(e); + } + } + + @Override + public void onComplete() { + downstream.onComplete(); + } + + @Override + public void cancel() { + upstream.cancel(); + } + + @Override + public void request(long n) { + upstream.request(n); + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorNext.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorNext.java index 7c9de4a748b..cb33b81a2ff 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorNext.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorNext.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorReturn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorReturn.java index 4fe88985a4f..85a375fac9c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorReturn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorReturn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublish.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublish.java index 49e75fc1fd4..b05bc8b748b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublish.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublish.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,9 +23,11 @@ import io.reactivex.rxjava3.flowables.ConnectableFlowable; import io.reactivex.rxjava3.functions.Consumer; import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** @@ -60,14 +62,6 @@ public Publisher source() { return source; } - /** - * The internal buffer size of this FlowablePublishAlt operator. - * @return The internal buffer size of this FlowablePublishAlt operator. - */ - public int publishBufferSize() { - return bufferSize; - } - @Override public void connect(Consumer connection) { PublishConnection conn; @@ -232,7 +226,7 @@ public void onSubscribe(Subscription s) { public void onNext(T t) { // we expect upstream to honor backpressure requests if (sourceMode == QueueSubscription.NONE && !queue.offer(t)) { - onError(new MissingBackpressureException("Prefetch queue is full?!")); + onError(new QueueOverflowException()); return; } // since many things can happen concurrently, we have a common dispatch diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishMulticast.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishMulticast.java index 05e0e7a9074..08d0e400586 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishMulticast.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishMulticast.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.operators.flowable; @@ -22,12 +19,12 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** @@ -124,7 +121,7 @@ public void cancel() { } } - static final class MulticastProcessor extends Flowable implements FlowableSubscriber, Disposable { + static final class MulticastProcessor extends Flowable implements FlowableSubscriber { @SuppressWarnings("rawtypes") static final MulticastSubscription[] EMPTY = new MulticastSubscription[0]; @@ -192,19 +189,19 @@ public void onSubscribe(Subscription s) { } } - @Override - public void dispose() { - SubscriptionHelper.cancel(upstream); - if (wip.getAndIncrement() == 0) { - SimpleQueue q = queue; - if (q != null) { - q.clear(); + void dispose() { + if (!done) { + SubscriptionHelper.cancel(upstream); + if (wip.getAndIncrement() == 0) { + SimpleQueue q = queue; + if (q != null) { + q.clear(); + } } } } - @Override - public boolean isDisposed() { + boolean isDisposed() { return upstream.get() == SubscriptionHelper.CANCELLED; } @@ -215,7 +212,7 @@ public void onNext(T t) { } if (sourceMode == QueueSubscription.NONE && !queue.offer(t)) { upstream.get().cancel(); - onError(new MissingBackpressureException()); + onError(MissingBackpressureException.createDefault()); return; } drain(); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRange.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRange.java index 9c14349eb97..e2e3b9a6fbd 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRange.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRange.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,9 +17,9 @@ import io.reactivex.rxjava3.annotations.Nullable; import io.reactivex.rxjava3.core.Flowable; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; /** * Emits a range of integer values. diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRangeLong.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRangeLong.java index 8ae2f333ae6..3be56da6ef8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRangeLong.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRangeLong.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,9 +17,9 @@ import io.reactivex.rxjava3.annotations.Nullable; import io.reactivex.rxjava3.core.Flowable; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; /** * Emits a range of long values. diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduce.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduce.java index 2aa1d71db05..99bc8615194 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduce.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduce.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceMaybe.java index aded7967b88..6541fee6bb9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceSeedSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceSeedSingle.java index 715cb49c0af..a5a8cc40cba 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceSeedSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceSeedSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceWithSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceWithSingle.java index b2aaf836d74..9d27a19668f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceWithSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceWithSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRefCount.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRefCount.java index 1bce5a4dd75..0c9f17b0bd7 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRefCount.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRefCount.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeat.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeat.java index 3acb03fb76c..ffc90b8f4b4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeat.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeat.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeatUntil.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeatUntil.java index 70df0e949d8..1d527fa59c2 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeatUntil.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeatUntil.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeatWhen.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeatWhen.java index 5371930b5f4..a2bfa250e55 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeatWhen.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeatWhen.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReplay.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReplay.java index db8718a4336..11489490c73 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReplay.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReplay.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -118,10 +118,11 @@ public static ConnectableFlowable create(Flowable source, } /** - * Creates a OperatorReplay instance to replay values of the given source observable. - * @param source the source observable - * @param bufferFactory the factory to instantiate the appropriate buffer when the observable becomes active - * @return the connectable observable + * Creates a OperatorReplay instance to replay values of the given source {@code Flowable}. + * @param the value type + * @param source the source {@code Flowable} to use + * @param bufferFactory the factory to instantiate the appropriate buffer when the {@code Flowable} becomes active + * @return the {@code ConnectableFlowable} instance */ static ConnectableFlowable create(Flowable source, final Supplier> bufferFactory) { @@ -179,7 +180,7 @@ public void connect(Consumer connection) { } // create a new subscriber-to-source - ReplaySubscriber u = new ReplaySubscriber<>(buf); + ReplaySubscriber u = new ReplaySubscriber<>(buf, current); // try setting it as the current subscriber-to-source if (!current.compareAndSet(ps, u)) { // did not work, perhaps a new subscriber arrived @@ -246,14 +247,16 @@ static final class ReplaySubscriber final AtomicInteger management; - /** Contains the maximum element index the child Subscribers requested so far. Accessed while emitting is true. */ - long maxChildRequested; - /** Counts the outstanding upstream requests until the producer arrives. */ - long maxUpstreamRequested; + /** Tracks the amount already requested from the upstream. */ + long requestedFromUpstream; + + /** The current connection. */ + final AtomicReference> current; @SuppressWarnings("unchecked") - ReplaySubscriber(ReplayBuffer buffer) { + ReplaySubscriber(ReplayBuffer buffer, AtomicReference> current) { this.buffer = buffer; + this.current = current; this.management = new AtomicInteger(); this.subscribers = new AtomicReference<>(EMPTY); this.shouldConnect = new AtomicBoolean(); @@ -268,9 +271,7 @@ public boolean isDisposed() { @Override public void dispose() { subscribers.set(TERMINATED); - // unlike OperatorPublish, we can't null out the terminated so - // late subscribers can still get replay - // current.compareAndSet(ReplaySubscriber.this, null); + current.compareAndSet(ReplaySubscriber.this, null); // we don't care if it fails because it means the current has // been replaced in the meantime SubscriptionHelper.cancel(this); @@ -284,9 +285,6 @@ public void dispose() { */ @SuppressWarnings("unchecked") boolean add(InnerSubscription producer) { - if (producer == null) { - throw new NullPointerException(); - } // the state can change so we do a CAS loop to achieve atomicity for (;;) { // get the current producer array @@ -415,7 +413,8 @@ public void onComplete() { * Coordinates the request amounts of various child Subscribers. */ void manageRequests() { - if (management.getAndIncrement() != 0) { + AtomicInteger m = management; + if (m.getAndIncrement() != 0) { return; } int missed = 1; @@ -424,46 +423,29 @@ void manageRequests() { if (isDisposed()) { return; } + Subscription p = get(); - InnerSubscription[] a = subscribers.get(); - - long ri = maxChildRequested; - long maxTotalRequests = ri; - - for (InnerSubscription rp : a) { - maxTotalRequests = Math.max(maxTotalRequests, rp.totalRequested.get()); - } + // only request when there is an upstream Subscription available + if (p != null) { + // how many items were requested so far + long alreadyRequested = requestedFromUpstream; + long downstreamMaxRequest = alreadyRequested; - long ur = maxUpstreamRequested; - Subscription p = get(); + // find out the maximum total requested of the current subscribers + for (InnerSubscription rp : subscribers.get()) { + downstreamMaxRequest = Math.max(downstreamMaxRequest, rp.totalRequested.get()); + } - long diff = maxTotalRequests - ri; - if (diff != 0L) { - maxChildRequested = maxTotalRequests; - if (p != null) { - if (ur != 0L) { - maxUpstreamRequested = 0L; - p.request(ur + diff); - } else { - p.request(diff); - } - } else { - // collect upstream request amounts until there is a producer for them - long u = ur + diff; - if (u < 0) { - u = Long.MAX_VALUE; - } - maxUpstreamRequested = u; + // how much more to request from the upstream + long diff = downstreamMaxRequest - alreadyRequested; + if (diff != 0L) { + // save the new maximum requested + requestedFromUpstream = downstreamMaxRequest; + p.request(diff); } - } else - // if there were outstanding upstream requests and we have a producer - if (ur != 0L && p != null) { - maxUpstreamRequested = 0L; - // fire the accumulated requests - p.request(ur); } - missed = management.addAndGet(-missed); + missed = m.addAndGet(-missed); if (missed == 0) { break; } @@ -563,6 +545,7 @@ public void dispose() { } /** * Convenience method to auto-cast the index object. + * @param type to cast index object * @return the current index object */ @SuppressWarnings("unchecked") @@ -668,6 +651,8 @@ public void replay(InnerSubscription output) { output.dispose(); if (!NotificationLite.isError(o) && !NotificationLite.isComplete(o)) { child.onError(err); + } else { + RxJavaPlugins.onError(err); } return; } @@ -717,7 +702,7 @@ static final class Node extends AtomicReference { * * @param the value type */ - static class BoundedReplayBuffer extends AtomicReference implements ReplayBuffer { + abstract static class BoundedReplayBuffer extends AtomicReference implements ReplayBuffer { private static final long serialVersionUID = 2346567790059478686L; @@ -829,11 +814,6 @@ public final void replay(InnerSubscription output) { output.emitting = true; } for (;;) { - if (output.isDisposed()) { - output.index = null; - return; - } - long r = output.get(); boolean unbounded = r == Long.MAX_VALUE; // NOPMD long e = 0L; @@ -847,6 +827,11 @@ public final void replay(InnerSubscription output) { } while (r != 0) { + if (output.isDisposed()) { + output.index = null; + return; + } + Node v = node.get(); if (v != null) { Object o = leaveTransform(v.value); @@ -861,6 +846,8 @@ public final void replay(InnerSubscription output) { output.dispose(); if (!NotificationLite.isError(o) && !NotificationLite.isComplete(o)) { output.child.onError(err); + } else { + RxJavaPlugins.onError(err); } return; } @@ -870,10 +857,11 @@ public final void replay(InnerSubscription output) { } else { break; } - if (output.isDisposed()) { - output.index = null; - return; - } + } + + if (r == 0 && output.isDisposed()) { + output.index = null; + return; } if (e != 0L) { @@ -917,9 +905,7 @@ Object leaveTransform(Object value) { * Override this method to truncate a non-terminated buffer * based on its current properties. */ - void truncate() { - - } + abstract void truncate(); /** * Override this method to truncate a terminated buffer * based on its properties (i.e., truncate but the very last node). @@ -1021,7 +1007,7 @@ void truncate() { int e = 0; for (;;) { - if (next != null && size > 1) { // never truncate the very last item just added + if (size > 1) { // never truncate the very last item just added if (size > limit) { e++; size--; @@ -1056,7 +1042,7 @@ void truncateFinal() { int e = 0; for (;;) { - if (next != null && size > 1) { + if (size > 1) { Timed v = (Timed)next.value; if (v.time() <= timeLimit) { e++; @@ -1149,31 +1135,6 @@ public void accept(Disposable r) { } } - static final class ConnectableFlowableReplay extends ConnectableFlowable { - private final ConnectableFlowable cf; - private final Flowable flowable; - - ConnectableFlowableReplay(ConnectableFlowable cf, Flowable flowable) { - this.cf = cf; - this.flowable = flowable; - } - - @Override - public void connect(Consumer connection) { - cf.connect(connection); - } - - @Override - public void reset() { - cf.reset(); - } - - @Override - protected void subscribeActual(Subscriber s) { - flowable.subscribe(s); - } - } - static final class ReplayBufferSupplier implements Supplier> { final int bufferSize; @@ -1241,7 +1202,7 @@ public void subscribe(Subscriber child) { return; } // create a new subscriber to source - ReplaySubscriber u = new ReplaySubscriber<>(buf); + ReplaySubscriber u = new ReplaySubscriber<>(buf, curr); // let's try setting it as the current subscriber-to-source if (!curr.compareAndSet(null, u)) { // didn't work, maybe someone else did it or the current subscriber diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryBiPredicate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryBiPredicate.java index 62b4852849a..8c8a0e960e9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryBiPredicate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryBiPredicate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryPredicate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryPredicate.java index 75350871c49..a954a093005 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryPredicate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryPredicate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryWhen.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryWhen.java index f4129d7be81..9babc654721 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryWhen.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryWhen.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSamplePublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSamplePublisher.java index 4a20a2b95f3..19474d2cc0f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSamplePublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSamplePublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -129,7 +129,7 @@ void emit() { BackpressureHelper.produced(requested, 1); } else { cancel(); - downstream.onError(new MissingBackpressureException("Couldn't emit value due to lack of requests!")); + downstream.onError(MissingBackpressureException.createDefault()); } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSampleTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSampleTimed.java index 17e1644749f..40551f4a8ed 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSampleTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSampleTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,6 +16,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.*; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.Consumer; import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; @@ -29,24 +31,25 @@ public final class FlowableSampleTimed extends AbstractFlowableWithUpstream onDropped; - public FlowableSampleTimed(Flowable source, long period, TimeUnit unit, Scheduler scheduler, boolean emitLast) { + public FlowableSampleTimed(Flowable source, long period, TimeUnit unit, Scheduler scheduler, boolean emitLast, Consumer onDropped) { super(source); this.period = period; this.unit = unit; this.scheduler = scheduler; this.emitLast = emitLast; + this.onDropped = onDropped; } @Override protected void subscribeActual(Subscriber s) { SerializedSubscriber serial = new SerializedSubscriber<>(s); if (emitLast) { - source.subscribe(new SampleTimedEmitLast<>(serial, period, unit, scheduler)); + source.subscribe(new SampleTimedEmitLast<>(serial, period, unit, scheduler, onDropped)); } else { - source.subscribe(new SampleTimedNoLast<>(serial, period, unit, scheduler)); + source.subscribe(new SampleTimedNoLast<>(serial, period, unit, scheduler, onDropped)); } } @@ -58,6 +61,7 @@ abstract static class SampleTimedSubscriber extends AtomicReference implem final long period; final TimeUnit unit; final Scheduler scheduler; + final Consumer onDropped; final AtomicLong requested = new AtomicLong(); @@ -65,11 +69,12 @@ abstract static class SampleTimedSubscriber extends AtomicReference implem Subscription upstream; - SampleTimedSubscriber(Subscriber actual, long period, TimeUnit unit, Scheduler scheduler) { + SampleTimedSubscriber(Subscriber actual, long period, TimeUnit unit, Scheduler scheduler, Consumer onDropped) { this.downstream = actual; this.period = period; this.unit = unit; this.scheduler = scheduler; + this.onDropped = onDropped; } @Override @@ -84,7 +89,17 @@ public void onSubscribe(Subscription s) { @Override public void onNext(T t) { - lazySet(t); + T oldValue = getAndSet(t); + if (oldValue != null && onDropped != null) { + try { + onDropped.accept(oldValue); + } catch (Throwable throwable) { + Exceptions.throwIfFatal(throwable); + cancelTimer(); + upstream.cancel(); + downstream.onError(throwable); + } + } } @Override @@ -125,7 +140,7 @@ void emit() { BackpressureHelper.produced(requested, 1); } else { cancel(); - downstream.onError(new MissingBackpressureException("Couldn't emit value due to lack of requests!")); + downstream.onError(MissingBackpressureException.createDefault()); } } } @@ -137,8 +152,8 @@ static final class SampleTimedNoLast extends SampleTimedSubscriber { private static final long serialVersionUID = -7139995637533111443L; - SampleTimedNoLast(Subscriber actual, long period, TimeUnit unit, Scheduler scheduler) { - super(actual, period, unit, scheduler); + SampleTimedNoLast(Subscriber actual, long period, TimeUnit unit, Scheduler scheduler, Consumer onDropped) { + super(actual, period, unit, scheduler, onDropped); } @Override @@ -158,8 +173,8 @@ static final class SampleTimedEmitLast extends SampleTimedSubscriber { final AtomicInteger wip; - SampleTimedEmitLast(Subscriber actual, long period, TimeUnit unit, Scheduler scheduler) { - super(actual, period, unit, scheduler); + SampleTimedEmitLast(Subscriber actual, long period, TimeUnit unit, Scheduler scheduler, Consumer onDropped) { + super(actual, period, unit, scheduler, onDropped); this.wip = new AtomicInteger(1); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScalarXMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScalarXMap.java index 4abae183b4f..cb6471b878d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScalarXMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScalarXMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScan.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScan.java index 01991892041..84c348adfb0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScan.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScan.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScanSeed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScanSeed.java index 21c88ab7bfe..2ffbc6c8e24 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScanSeed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScanSeed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import java.util.Objects; @@ -20,10 +21,10 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.operators.SimplePlainQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class FlowableScanSeed extends AbstractFlowableWithUpstream { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSequenceEqual.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSequenceEqual.java index cc65e1d37e8..8dadbe01617 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSequenceEqual.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSequenceEqual.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,10 +20,11 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.BiPredicate; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.AtomicThrowable; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; public final class FlowableSequenceEqual extends Flowable { final Publisher first; @@ -299,7 +300,7 @@ public void onSubscribe(Subscription s) { public void onNext(T t) { if (sourceMode == QueueSubscription.NONE) { if (!queue.offer(t)) { - onError(new MissingBackpressureException()); + onError(MissingBackpressureException.createDefault()); return; } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSequenceEqualSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSequenceEqualSingle.java index 05d99e4e49b..5ede5990f9d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSequenceEqualSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSequenceEqualSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -25,6 +25,7 @@ import io.reactivex.rxjava3.internal.operators.flowable.FlowableSequenceEqual.*; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.AtomicThrowable; +import io.reactivex.rxjava3.operators.SimpleQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class FlowableSequenceEqualSingle extends Single implements FuseToFlowable { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSerialized.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSerialized.java index 2cd7df33690..4c43ff9c6f8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSerialized.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSerialized.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import org.reactivestreams.Subscriber; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingle.java index 068385289a4..02077e5444d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingleMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingleMaybe.java index fac74c9cd86..51beeff27c9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingleMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingleMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle.java index c24b45a760f..8a4f7fe339e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingleSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkip.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkip.java index 2aecef3e106..d9c2f49d1ef 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkip.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkip.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLast.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLast.java index 5908d6d0b0c..9f19ee86ba6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLast.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLast.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLastTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLastTimed.java index b56224cbdf5..66f7d240f50 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLastTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLastTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,9 +19,9 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; public final class FlowableSkipLastTimed extends AbstractFlowableWithUpstream { final long time; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipUntil.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipUntil.java index 8de843142ce..a7c51f99411 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipUntil.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipUntil.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,9 +18,9 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; public final class FlowableSkipUntil extends AbstractFlowableWithUpstream { final Publisher other; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipWhile.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipWhile.java index 62ee5ebdbea..be88184f380 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipWhile.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipWhile.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOn.java index b7fdd91e9f3..7d4a51f0f2d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchIfEmpty.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchIfEmpty.java index b2ad9db0d09..1d45216f149 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchIfEmpty.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchIfEmpty.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchMap.java index 7c6c1006caf..4d4521c655a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,10 +21,11 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class FlowableSwitchMap extends AbstractFlowableWithUpstream { @@ -180,12 +181,9 @@ public void cancel() { @SuppressWarnings("unchecked") void disposeInner() { - SwitchMapInnerSubscriber a = active.get(); - if (a != CANCELLED) { - a = active.getAndSet((SwitchMapInnerSubscriber)CANCELLED); - if (a != CANCELLED && a != null) { - a.cancel(); - } + SwitchMapInnerSubscriber a = active.getAndSet((SwitchMapInnerSubscriber)CANCELLED); + if (a != CANCELLED && a != null) { + a.cancel(); } } @@ -201,7 +199,6 @@ void drain() { for (;;) { if (cancelled) { - active.lazySet(null); return; } @@ -228,26 +225,6 @@ void drain() { SwitchMapInnerSubscriber inner = active.get(); SimpleQueue q = inner != null ? inner.queue : null; if (q != null) { - if (inner.done) { - if (!delayErrors) { - Throwable err = errors.get(); - if (err != null) { - disposeInner(); - errors.tryTerminateConsumer(a); - return; - } else - if (q.isEmpty()) { - active.compareAndSet(inner, null); - continue; - } - } else { - if (q.isEmpty()) { - active.compareAndSet(inner, null); - continue; - } - } - } - long r = requested.get(); long e = 0L; boolean retry = false; @@ -306,6 +283,28 @@ void drain() { e++; } + if (e == r) { + if (inner.done) { + if (!delayErrors) { + Throwable err = errors.get(); + if (err != null) { + disposeInner(); + errors.tryTerminateConsumer(a); + return; + } else + if (q.isEmpty()) { + active.compareAndSet(inner, null); + continue; + } + } else { + if (q.isEmpty()) { + active.compareAndSet(inner, null); + continue; + } + } + } + } + if (e != 0L) { if (!cancelled) { if (r != Long.MAX_VALUE) { @@ -382,7 +381,7 @@ public void onNext(R t) { SwitchMapSubscriber p = parent; if (index == p.unique) { if (fusionMode == QueueSubscription.NONE && !queue.offer(t)) { - onError(new MissingBackpressureException("Queue full?!")); + onError(new QueueOverflowException()); return; } p.drain(); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTake.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTake.java index 15d06f087fe..ea5ca1c4e13 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTake.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTake.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLast.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLast.java index 062135b47c9..ad26f45124a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLast.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLast.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -119,8 +119,12 @@ void drain() { a.onNext(v); e++; } - if (e != 0L && r != Long.MAX_VALUE) { - r = requested.addAndGet(-e); + if (isEmpty()) { + a.onComplete(); + return; + } + if (e != 0L) { + r = BackpressureHelper.produced(requested, e); } } } while (wip.decrementAndGet() != 0); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastOne.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastOne.java index e4b674704d0..43d3bf44462 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastOne.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastOne.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import org.reactivestreams.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastTimed.java index a7c2ab3343b..b42b5717ce3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,9 +19,9 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; public final class FlowableTakeLastTimed extends AbstractFlowableWithUpstream { final long count; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakePublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakePublisher.java index 9a30bda905f..b105b34ca21 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakePublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakePublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntil.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntil.java index 9c927cca5d8..6ea62f6975c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntil.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntil.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntilPredicate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntilPredicate.java index a8ec19c22a4..a57bb14c0ab 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntilPredicate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntilPredicate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeWhile.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeWhile.java index 5bcd8157d34..ea8d4f13eb6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeWhile.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeWhile.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleFirstTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleFirstTimed.java index 918e2ea6d75..44499ec2556 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleFirstTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleFirstTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,6 +16,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.Consumer; import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; @@ -32,44 +34,53 @@ public final class FlowableThrottleFirstTimed extends AbstractFlowableWithUps final long timeout; final TimeUnit unit; final Scheduler scheduler; + final Consumer onDropped; - public FlowableThrottleFirstTimed(Flowable source, long timeout, TimeUnit unit, Scheduler scheduler) { + public FlowableThrottleFirstTimed(Flowable source, + long timeout, + TimeUnit unit, + Scheduler scheduler, + Consumer onDropped) { super(source); this.timeout = timeout; this.unit = unit; this.scheduler = scheduler; + this.onDropped = onDropped; } @Override protected void subscribeActual(Subscriber s) { source.subscribe(new DebounceTimedSubscriber<>( new SerializedSubscriber<>(s), - timeout, unit, scheduler.createWorker())); + timeout, unit, scheduler.createWorker(), + onDropped)); } static final class DebounceTimedSubscriber extends AtomicLong implements FlowableSubscriber, Subscription, Runnable { - private static final long serialVersionUID = -9102637559663639004L; + final Subscriber downstream; final long timeout; final TimeUnit unit; final Scheduler.Worker worker; - + final Consumer onDropped; Subscription upstream; - final SequentialDisposable timer = new SequentialDisposable(); - volatile boolean gate; - boolean done; - DebounceTimedSubscriber(Subscriber actual, long timeout, TimeUnit unit, Worker worker) { + DebounceTimedSubscriber(Subscriber actual, + long timeout, + TimeUnit unit, + Worker worker, + Consumer onDropped) { this.downstream = actual; this.timeout = timeout; this.unit = unit; this.worker = worker; + this.onDropped = onDropped; } @Override @@ -94,9 +105,10 @@ public void onNext(T t) { downstream.onNext(t); BackpressureHelper.produced(this, 1); } else { + upstream.cancel(); done = true; - cancel(); - downstream.onError(new MissingBackpressureException("Could not deliver value due to lack of requests")); + downstream.onError(MissingBackpressureException.createDefault()); + worker.dispose(); return; } @@ -106,6 +118,16 @@ public void onNext(T t) { } timer.replace(worker.schedule(this, timeout, unit)); + } else if (onDropped != null) { + try { + onDropped.accept(t); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.cancel(); + done = true; + downstream.onError(ex); + worker.dispose(); + } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleLatest.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleLatest.java index 989eaaf4b2a..e28e5f09dfe 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleLatest.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleLatest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,9 +19,11 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.exceptions.MissingBackpressureException; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.functions.Consumer; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** * Emits the next or latest item when the given time elapses. @@ -44,19 +46,24 @@ public final class FlowableThrottleLatest extends AbstractFlowableWithUpstrea final boolean emitLast; + final Consumer onDropped; + public FlowableThrottleLatest(Flowable source, - long timeout, TimeUnit unit, Scheduler scheduler, - boolean emitLast) { + long timeout, TimeUnit unit, + Scheduler scheduler, + boolean emitLast, + Consumer onDropped) { super(source); this.timeout = timeout; this.unit = unit; this.scheduler = scheduler; this.emitLast = emitLast; + this.onDropped = onDropped; } @Override protected void subscribeActual(Subscriber s) { - source.subscribe(new ThrottleLatestSubscriber<>(s, timeout, unit, scheduler.createWorker(), emitLast)); + source.subscribe(new ThrottleLatestSubscriber<>(s, timeout, unit, scheduler.createWorker(), emitLast, onDropped)); } static final class ThrottleLatestSubscriber @@ -79,6 +86,8 @@ static final class ThrottleLatestSubscriber final AtomicLong requested; + final Consumer onDropped; + Subscription upstream; volatile boolean done; @@ -93,8 +102,10 @@ static final class ThrottleLatestSubscriber boolean timerRunning; ThrottleLatestSubscriber(Subscriber downstream, - long timeout, TimeUnit unit, Scheduler.Worker worker, - boolean emitLast) { + long timeout, TimeUnit unit, + Scheduler.Worker worker, + boolean emitLast, + Consumer onDropped) { this.downstream = downstream; this.timeout = timeout; this.unit = unit; @@ -102,6 +113,7 @@ static final class ThrottleLatestSubscriber this.emitLast = emitLast; this.latest = new AtomicReference<>(); this.requested = new AtomicLong(); + this.onDropped = onDropped; } @Override @@ -115,7 +127,17 @@ public void onSubscribe(Subscription s) { @Override public void onNext(T t) { - latest.set(t); + T old = latest.getAndSet(t); + if (onDropped != null && old != null) { + try { + onDropped.accept(old); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.cancel(); + error = ex; + done = true; + } + } drain(); } @@ -145,6 +167,22 @@ public void cancel() { upstream.cancel(); worker.dispose(); if (getAndIncrement() == 0) { + clear(); + } + } + + void clear() { + if (onDropped != null) { + T v = latest.getAndSet(null); + if (v != null) { + try { + onDropped.accept(v); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + RxJavaPlugins.onError(ex); + } + } + } else { latest.lazySet(null); } } @@ -170,14 +208,27 @@ void drain() { for (;;) { if (cancelled) { - latest.lazySet(null); + clear(); return; } boolean d = done; + Throwable error = this.error; if (d && error != null) { - latest.lazySet(null); + if (onDropped != null) { + T v = latest.getAndSet(null); + if (v != null) { + try { + onDropped.accept(v); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + error = new CompositeException(error, ex); + } + } + } else { + latest.lazySet(null); + } downstream.onError(error); worker.dispose(); return; @@ -187,19 +238,31 @@ void drain() { boolean empty = v == null; if (d) { - if (!empty && emitLast) { + if (!empty) { v = latest.getAndSet(null); - long e = emitted; - if (e != requested.get()) { - emitted = e + 1; - downstream.onNext(v); - downstream.onComplete(); + if (emitLast) { + long e = emitted; + if (e != requested.get()) { + emitted = e + 1; + downstream.onNext(v); + downstream.onComplete(); + } else { + tryDropAndSignalMBE(v); + } } else { - downstream.onError(new MissingBackpressureException( - "Could not emit final value due to lack of requests")); + if (onDropped != null) { + try { + onDropped.accept(v); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + downstream.onError(ex); + worker.dispose(); + return; + } + } + downstream.onComplete(); } } else { - latest.lazySet(null); downstream.onComplete(); } worker.dispose(); @@ -222,8 +285,7 @@ void drain() { emitted = e + 1; } else { upstream.cancel(); - downstream.onError(new MissingBackpressureException( - "Could not emit value due to lack of requests")); + tryDropAndSignalMBE(v); worker.dispose(); return; } @@ -242,5 +304,18 @@ void drain() { } } } + + void tryDropAndSignalMBE(T valueToDrop) { + Throwable errorToSignal = MissingBackpressureException.createDefault(); + if (onDropped != null) { + try { + onDropped.accept(valueToDrop); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + errorToSignal = new CompositeException(errorToSignal, ex); + } + } + downstream.onError(errorToSignal); + } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeInterval.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeInterval.java index eb9ec1fbd9f..1601814c987 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeInterval.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeInterval.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeout.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeout.java index 976ab10a05c..506132f5953 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeout.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeout.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeoutTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeoutTimed.java index 351099500e9..67d612011da 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeoutTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeoutTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimer.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimer.java index 6c172320def..db45fe2e98d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -78,7 +78,7 @@ public void run() { downstream.onComplete(); } else { lazySet(EmptyDisposable.INSTANCE); - downstream.onError(new MissingBackpressureException("Can't deliver value due to lack of requests")); + downstream.onError(MissingBackpressureException.createDefault()); } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToList.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToList.java index 18d8a86de4b..3f03d93112e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToList.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToList.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -46,7 +46,7 @@ protected void subscribeActual(Subscriber s) { static final class ToListSubscriber> extends DeferredScalarSubscription - implements FlowableSubscriber, Subscription { + implements FlowableSubscriber { private static final long serialVersionUID = -8134157938864266736L; Subscription upstream; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToListSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToListSingle.java index aea4eb32701..5e65b48e089 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToListSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToListSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUnsubscribeOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUnsubscribeOn.java index ee9d8f3cc7d..dd8c4ce4cf3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUnsubscribeOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUnsubscribeOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUsing.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUsing.java index 5a5b177d35b..8f34a6e4140 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUsing.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUsing.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -117,7 +117,6 @@ public void onError(Throwable t) { } } - upstream.cancel(); if (innerError != null) { downstream.onError(new CompositeException(t, innerError)); } else { @@ -125,7 +124,6 @@ public void onError(Throwable t) { } } else { downstream.onError(t); - upstream.cancel(); disposeResource(); } } @@ -143,11 +141,9 @@ public void onComplete() { } } - upstream.cancel(); downstream.onComplete(); } else { downstream.onComplete(); - upstream.cancel(); disposeResource(); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindow.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindow.java index e00ed99edf5..85ab5a5e0b1 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindow.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindow.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,11 +19,10 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.BackpressureHelper; -import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.processors.*; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; +import io.reactivex.rxjava3.processors.UnicastProcessor; public final class FlowableWindow extends AbstractFlowableWithUpstream> { final long size; @@ -358,10 +357,6 @@ public void onSubscribe(Subscription s) { @Override public void onNext(T t) { - if (done) { - return; - } - long i = index; UnicastProcessor newWindow = null; @@ -407,11 +402,6 @@ public void onNext(T t) { @Override public void onError(Throwable t) { - if (done) { - RxJavaPlugins.onError(t); - return; - } - for (Processor w : windows) { w.onError(t); } @@ -424,10 +414,6 @@ public void onError(Throwable t) { @Override public void onComplete() { - if (done) { - return; - } - for (Processor w : windows) { w.onComplete(); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowBoundary.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowBoundary.java index c86d3faab1d..2aad69dcb5e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowBoundary.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowBoundary.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -248,7 +248,7 @@ void drain() { } else { SubscriptionHelper.cancel(upstream); boundarySubscriber.dispose(); - errors.tryAddThrowableOrReport(new MissingBackpressureException("Could not deliver a window due to lack of requests")); + errors.tryAddThrowableOrReport(MissingBackpressureException.createDefault()); done = true; } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowBoundarySelector.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowBoundarySelector.java index f6248b33555..d6bffae2e13 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowBoundarySelector.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowBoundarySelector.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,10 +22,10 @@ import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; import io.reactivex.rxjava3.internal.queue.MpscLinkedQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimplePlainQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.UnicastProcessor; @@ -272,7 +272,7 @@ void drain() { upstream.cancel(); startSubscriber.cancel(); resources.dispose(); - error.tryAddThrowableOrReport(new MissingBackpressureException(FlowableWindowTimed.missingBackpressureMessage(emitted))); + error.tryAddThrowableOrReport(FlowableWindowTimed.missingBackpressureMessage(emitted)); upstreamDone = true; } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowSubscribeIntercept.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowSubscribeIntercept.java index 8f6cf0a2dac..8ef2204c97c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowSubscribeIntercept.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowSubscribeIntercept.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,4 +45,4 @@ protected void subscribeActual(Subscriber s) { boolean tryAbandon() { return !once.get() && once.compareAndSet(false, true); } -} \ No newline at end of file +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowTimed.java index 89b49e857a8..39e7de59ada 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,10 +23,10 @@ import io.reactivex.rxjava3.core.Scheduler.Worker; import io.reactivex.rxjava3.exceptions.MissingBackpressureException; import io.reactivex.rxjava3.internal.disposables.SequentialDisposable; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; import io.reactivex.rxjava3.internal.queue.MpscLinkedQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.operators.SimplePlainQueue; import io.reactivex.rxjava3.processors.UnicastProcessor; public final class FlowableWindowTimed extends AbstractFlowableWithUpstream> { @@ -213,7 +213,7 @@ void createFirstWindow() { upstream.request(Long.MAX_VALUE); } else { upstream.cancel(); - downstream.onError(new MissingBackpressureException(missingBackpressureMessage(emitted))); + downstream.onError(missingBackpressureMessage(emitted)); cleanupResources(); upstreamCancelled = true; @@ -282,7 +282,7 @@ else if (!isEmpty) { cleanupResources(); upstreamCancelled = true; - downstream.onError(new MissingBackpressureException(missingBackpressureMessage(emitted))); + downstream.onError(missingBackpressureMessage(emitted)); } else { emitted++; @@ -386,7 +386,7 @@ void createFirstWindow() { upstream.request(Long.MAX_VALUE); } else { upstream.cancel(); - downstream.onError(new MissingBackpressureException(missingBackpressureMessage(emitted))); + downstream.onError(missingBackpressureMessage(emitted)); cleanupResources(); upstreamCancelled = true; @@ -499,7 +499,7 @@ UnicastProcessor createNewWindow(UnicastProcessor window) { cleanupResources(); upstreamCancelled = true; - downstream.onError(new MissingBackpressureException(missingBackpressureMessage(emitted))); + downstream.onError(missingBackpressureMessage(emitted)); } else { this.emitted = ++emitted; @@ -584,7 +584,7 @@ void createFirstWindow() { upstream.request(Long.MAX_VALUE); } else { upstream.cancel(); - downstream.onError(new MissingBackpressureException(missingBackpressureMessage(emitted))); + downstream.onError(missingBackpressureMessage(emitted)); cleanupResources(); upstreamCancelled = true; @@ -654,7 +654,7 @@ void drain() { } } else { upstream.cancel(); - Throwable ex = new MissingBackpressureException(missingBackpressureMessage(emitted)); + Throwable ex = missingBackpressureMessage(emitted); for (UnicastProcessor window : windows) { window.onError(ex); } @@ -717,8 +717,8 @@ public void run() { } } - static String missingBackpressureMessage(long index) { - return "Unable to emit the next window (#" + index + ") due to lack of requests. Please make sure the downstream is ready to consume windows."; + static MissingBackpressureException missingBackpressureMessage(long index) { + return new MissingBackpressureException("Unable to emit the next window (#" + index + ") due to lack of requests. Please make sure the downstream is ready to consume windows."); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWithLatestFrom.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWithLatestFrom.java index 81d3544dd0f..cad9f3c0ca3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWithLatestFrom.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWithLatestFrom.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,8 +21,8 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.BiFunction; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; import io.reactivex.rxjava3.subscribers.SerializedSubscriber; public final class FlowableWithLatestFrom extends AbstractFlowableWithUpstream { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWithLatestFromMany.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWithLatestFromMany.java index be9166a16dd..77d05277292 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWithLatestFromMany.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWithLatestFromMany.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import java.util.Arrays; @@ -22,9 +23,9 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZip.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZip.java index 77011a5a2de..de680b19afb 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZip.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZip.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,10 +22,11 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; public final class FlowableZip extends Flowable { @@ -191,23 +192,12 @@ void drain() { for (int j = 0; j < n; j++) { ZipSubscriber inner = qs[j]; if (values[j] == null) { + boolean d = inner.done; + SimpleQueue q = inner.queue; + T v = null; try { - boolean d = inner.done; - SimpleQueue q = inner.queue; - T v = q != null ? q.poll() : null; - - boolean sourceEmpty = v == null; - if (d && sourceEmpty) { - cancelAll(); - errors.tryTerminateConsumer(a); - return; - } - if (!sourceEmpty) { - values[j] = v; - } else { - empty = true; - } + v = q != null ? q.poll() : null; } catch (Throwable ex) { Exceptions.throwIfFatal(ex); @@ -217,6 +207,18 @@ void drain() { errors.tryTerminateConsumer(a); return; } + d = true; + } + + boolean sourceEmpty = v == null; + if (d && sourceEmpty) { + cancelAll(); + errors.tryTerminateConsumer(a); + return; + } + if (!sourceEmpty) { + values[j] = v; + } else { empty = true; } } @@ -259,20 +261,11 @@ void drain() { for (int j = 0; j < n; j++) { ZipSubscriber inner = qs[j]; if (values[j] == null) { + boolean d = inner.done; + SimpleQueue q = inner.queue; + T v = null; try { - boolean d = inner.done; - SimpleQueue q = inner.queue; - T v = q != null ? q.poll() : null; - - boolean empty = v == null; - if (d && empty) { - cancelAll(); - errors.tryTerminateConsumer(a); - return; - } - if (!empty) { - values[j] = v; - } + v = q != null ? q.poll() : null; } catch (Throwable ex) { Exceptions.throwIfFatal(ex); errors.tryAddThrowableOrReport(ex); @@ -281,6 +274,16 @@ void drain() { errors.tryTerminateConsumer(a); return; } + d = true; + } + boolean empty = v == null; + if (d && empty) { + cancelAll(); + errors.tryTerminateConsumer(a); + return; + } + if (!empty) { + values[j] = v; } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipIterable.java index 1fb9777a50a..25d4df529d8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/AbstractMaybeWithUpstream.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/AbstractMaybeWithUpstream.java index ed559c96dc1..348bb482271 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/AbstractMaybeWithUpstream.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/AbstractMaybeWithUpstream.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeAmb.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeAmb.java index b87390e847a..802075b2aba 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeAmb.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeAmb.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCache.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCache.java index 05c15937072..f9080a12829 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCache.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCache.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserver.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserver.java index 774511f291c..c94c7d49292 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArray.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArray.java index f77a59c364f..889e229b649 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArray.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArray.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArrayDelayError.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArrayDelayError.java index e889adfe1a3..3b4b87399ae 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArrayDelayError.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArrayDelayError.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatIterable.java index ee6e87cbe07..b777f4c751e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeContains.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeContains.java index 8737c6ae372..c1154067f53 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeContains.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeContains.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCount.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCount.java index d687e6ac1e7..cd2bececf10 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCount.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCount.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCreate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCreate.java index 24293b895b2..1a6bc60d313 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCreate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCreate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDefer.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDefer.java index ccba4e00413..a1ffacef747 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDefer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDefer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelay.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelay.java index 6885763cbd3..5f130107819 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelay.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelay.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -33,16 +33,19 @@ public final class MaybeDelay extends AbstractMaybeWithUpstream { final Scheduler scheduler; - public MaybeDelay(MaybeSource source, long delay, TimeUnit unit, Scheduler scheduler) { + final boolean delayError; + + public MaybeDelay(MaybeSource source, long delay, TimeUnit unit, Scheduler scheduler, boolean delayError) { super(source); this.delay = delay; this.unit = unit; this.scheduler = scheduler; + this.delayError = delayError; } @Override protected void subscribeActual(MaybeObserver observer) { - source.subscribe(new DelayMaybeObserver<>(observer, delay, unit, scheduler)); + source.subscribe(new DelayMaybeObserver<>(observer, delay, unit, scheduler, delayError)); } static final class DelayMaybeObserver @@ -59,15 +62,18 @@ static final class DelayMaybeObserver final Scheduler scheduler; + final boolean delayError; + T value; Throwable error; - DelayMaybeObserver(MaybeObserver actual, long delay, TimeUnit unit, Scheduler scheduler) { + DelayMaybeObserver(MaybeObserver actual, long delay, TimeUnit unit, Scheduler scheduler, boolean delayError) { this.downstream = actual; this.delay = delay; this.unit = unit; this.scheduler = scheduler; + this.delayError = delayError; } @Override @@ -105,21 +111,21 @@ public void onSubscribe(Disposable d) { @Override public void onSuccess(T value) { this.value = value; - schedule(); + schedule(delay); } @Override public void onError(Throwable e) { this.error = e; - schedule(); + schedule(delayError ? delay : 0); } @Override public void onComplete() { - schedule(); + schedule(delay); } - void schedule() { + void schedule(long delay) { DisposableHelper.replace(this, scheduler.scheduleDirect(this, delay, unit)); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayOtherPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayOtherPublisher.java index 7797a968a5a..eebddc3c872 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayOtherPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayOtherPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelaySubscriptionOtherPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelaySubscriptionOtherPublisher.java index 7de18c70a50..7cd54da714b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelaySubscriptionOtherPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelaySubscriptionOtherPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayWithCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayWithCompletable.java index 6bdc5d1a98e..ecbd84a274a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayWithCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayWithCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDematerialize.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDematerialize.java new file mode 100644 index 00000000000..80b76d3171e --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDematerialize.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.internal.disposables.DisposableHelper; + +import java.util.Objects; + +/** + * Maps the success value of the source to a Notification, then + * maps it back to the corresponding signal type. + *

History: 2.2.4 - experimental + * @param the element type of the source + * @param the element type of the Notification and result + * @since 3.0.0 + */ +public final class MaybeDematerialize extends AbstractMaybeWithUpstream { + + final Function> selector; + + public MaybeDematerialize(Maybe source, Function> selector) { + super(source); + this.selector = selector; + } + + @Override + protected void subscribeActual(MaybeObserver observer) { + source.subscribe(new DematerializeObserver<>(observer, selector)); + } + + static final class DematerializeObserver implements MaybeObserver, Disposable { + + final MaybeObserver downstream; + + final Function> selector; + + Disposable upstream; + + DematerializeObserver(MaybeObserver downstream, + Function> selector) { + this.downstream = downstream; + this.selector = selector; + } + + @Override + public void dispose() { + upstream.dispose(); + } + + @Override + public boolean isDisposed() { + return upstream.isDisposed(); + } + + @Override + public void onSubscribe(Disposable d) { + if (DisposableHelper.validate(upstream, d)) { + upstream = d; + downstream.onSubscribe(this); + } + } + + @Override + public void onSuccess(T t) { + Notification notification; + + try { + notification = Objects.requireNonNull(selector.apply(t), "The selector returned a null Notification"); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + downstream.onError(ex); + return; + } + if (notification.isOnNext()) { + downstream.onSuccess(notification.getValue()); + } else if (notification.isOnComplete()) { + downstream.onComplete(); + } else { + downstream.onError(notification.getError()); + } + } + + @Override + public void onError(Throwable e) { + downstream.onError(e); + } + + @Override + public void onComplete() { + downstream.onComplete(); + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDetach.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDetach.java index 595c3629171..7dad3b0cf27 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDetach.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDetach.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoAfterSuccess.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoAfterSuccess.java index 28943223f0e..c8f47997892 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoAfterSuccess.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoAfterSuccess.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoFinally.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoFinally.java index 0078cf88b12..0d8dfe8de27 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoFinally.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoFinally.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnEvent.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnEvent.java index eccc36c6068..a2771dcb8ce 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnEvent.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnEvent.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnLifecycle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnLifecycle.java new file mode 100644 index 00000000000..03993293620 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnLifecycle.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.disposables.*; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + +/** + * Invokes callbacks upon {@code onSubscribe} from upstream and + * {@code dispose} from downstream. + * + * @param the element type of the flow + * @since 3.0.0 + */ +public final class MaybeDoOnLifecycle extends AbstractMaybeWithUpstream { + + final Consumer onSubscribe; + + final Action onDispose; + + public MaybeDoOnLifecycle(Maybe upstream, Consumer onSubscribe, + Action onDispose) { + super(upstream); + this.onSubscribe = onSubscribe; + this.onDispose = onDispose; + } + + @Override + protected void subscribeActual(MaybeObserver observer) { + source.subscribe(new MaybeLifecycleObserver<>(observer, onSubscribe, onDispose)); + } + + static final class MaybeLifecycleObserver implements MaybeObserver, Disposable { + + final MaybeObserver downstream; + + final Consumer onSubscribe; + + final Action onDispose; + + Disposable upstream; + + MaybeLifecycleObserver(MaybeObserver downstream, Consumer onSubscribe, Action onDispose) { + this.downstream = downstream; + this.onSubscribe = onSubscribe; + this.onDispose = onDispose; + } + + @Override + public void onSubscribe(@NonNull Disposable d) { + // this way, multiple calls to onSubscribe can show up in tests that use doOnSubscribe to validate behavior + try { + onSubscribe.accept(d); + } catch (Throwable e) { + Exceptions.throwIfFatal(e); + d.dispose(); + this.upstream = DisposableHelper.DISPOSED; + EmptyDisposable.error(e, downstream); + return; + } + if (DisposableHelper.validate(this.upstream, d)) { + this.upstream = d; + downstream.onSubscribe(this); + } + } + + @Override + public void onSuccess(@NonNull T t) { + if (upstream != DisposableHelper.DISPOSED) { + upstream = DisposableHelper.DISPOSED; + downstream.onSuccess(t); + } + } + + @Override + public void onError(@NonNull Throwable e) { + if (upstream != DisposableHelper.DISPOSED) { + upstream = DisposableHelper.DISPOSED; + downstream.onError(e); + } else { + RxJavaPlugins.onError(e); + } + } + + @Override + public void onComplete() { + if (upstream != DisposableHelper.DISPOSED) { + upstream = DisposableHelper.DISPOSED; + downstream.onComplete(); + } + } + + @Override + public void dispose() { + try { + onDispose.run(); + } catch (Throwable e) { + Exceptions.throwIfFatal(e); + RxJavaPlugins.onError(e); + } + upstream.dispose(); + upstream = DisposableHelper.DISPOSED; + } + + @Override + public boolean isDisposed() { + return upstream.isDisposed(); + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnTerminate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnTerminate.java index 7443b147a06..6c3494ac964 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnTerminate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnTerminate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEmpty.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEmpty.java index 4b3361998ed..a803b84fa9d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEmpty.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEmpty.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,7 +15,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.internal.disposables.EmptyDisposable; -import io.reactivex.rxjava3.internal.fuseable.ScalarSupplier; +import io.reactivex.rxjava3.operators.ScalarSupplier; /** * Signals an onComplete. diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEqualSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEqualSingle.java index ddcfc7b3c5c..bf940b82234 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEqualSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEqualSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeError.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeError.java index fc2f50066ef..ed9c391f021 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeError.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeError.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeErrorCallable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeErrorCallable.java index 20bb1e03a8c..360b7299337 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeErrorCallable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeErrorCallable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFilter.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFilter.java index 2ddf5fff277..833edb75f3e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFilter.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFilter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFilterSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFilterSingle.java index 05354478819..aa3cae5e5cc 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFilterSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFilterSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapBiSelector.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapBiSelector.java index da5cfe56b89..c57caee8f7f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapBiSelector.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapBiSelector.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapCompletable.java index 10fc003bf8a..1611fddfff7 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableFlowable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableFlowable.java index 40ca98c3516..322a73177f3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableFlowable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableFlowable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableObservable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableObservable.java index c5c24995b1c..2018274b1a0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapNotification.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapNotification.java index e357938db2f..d91bd46da66 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapNotification.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapNotification.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -109,7 +109,9 @@ public void onSuccess(T value) { return; } - source.subscribe(new InnerObserver()); + if (!isDisposed()) { + source.subscribe(new InnerObserver()); + } } @Override @@ -124,7 +126,9 @@ public void onError(Throwable e) { return; } - source.subscribe(new InnerObserver()); + if (!isDisposed()) { + source.subscribe(new InnerObserver()); + } } @Override @@ -139,7 +143,9 @@ public void onComplete() { return; } - source.subscribe(new InnerObserver()); + if (!isDisposed()) { + source.subscribe(new InnerObserver()); + } } final class InnerObserver implements MaybeObserver { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingle.java index 2199ea470ba..e88dd6fc3d2 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,7 +13,6 @@ package io.reactivex.rxjava3.internal.operators.maybe; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; @@ -25,10 +24,12 @@ /** * Maps the success value of the source MaybeSource into a Single. + *

History: 2.0.2 - experimental * @param the input value type * @param the result value type + * @since 2.1 */ -public final class MaybeFlatMapSingle extends Single { +public final class MaybeFlatMapSingle extends Maybe { final MaybeSource source; @@ -40,7 +41,7 @@ public MaybeFlatMapSingle(MaybeSource source, Function downstream) { + protected void subscribeActual(MaybeObserver downstream) { source.subscribe(new FlatMapMaybeObserver<>(downstream, mapper)); } @@ -50,11 +51,11 @@ static final class FlatMapMaybeObserver private static final long serialVersionUID = 4827726964688405508L; - final SingleObserver downstream; + final MaybeObserver downstream; final Function> mapper; - FlatMapMaybeObserver(SingleObserver actual, Function> mapper) { + FlatMapMaybeObserver(MaybeObserver actual, Function> mapper) { this.downstream = actual; this.mapper = mapper; } @@ -100,7 +101,7 @@ public void onError(Throwable e) { @Override public void onComplete() { - downstream.onError(new NoSuchElementException()); + downstream.onComplete(); } } @@ -108,9 +109,9 @@ static final class FlatMapSingleObserver implements SingleObserver { final AtomicReference parent; - final SingleObserver downstream; + final MaybeObserver downstream; - FlatMapSingleObserver(AtomicReference parent, SingleObserver downstream) { + FlatMapSingleObserver(AtomicReference parent, MaybeObserver downstream) { this.parent = parent; this.downstream = downstream; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingleElement.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingleElement.java deleted file mode 100644 index 49b7100575f..00000000000 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingleElement.java +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Copyright (c) 2016-present, RxJava Contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See - * the License for the specific language governing permissions and limitations under the License. - */ - -package io.reactivex.rxjava3.internal.operators.maybe; - -import java.util.Objects; -import java.util.concurrent.atomic.AtomicReference; - -import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.exceptions.Exceptions; -import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.disposables.DisposableHelper; - -/** - * Maps the success value of the source MaybeSource into a Single. - *

History: 2.0.2 - experimental - * @param the input value type - * @param the result value type - * @since 2.1 - */ -public final class MaybeFlatMapSingleElement extends Maybe { - - final MaybeSource source; - - final Function> mapper; - - public MaybeFlatMapSingleElement(MaybeSource source, Function> mapper) { - this.source = source; - this.mapper = mapper; - } - - @Override - protected void subscribeActual(MaybeObserver downstream) { - source.subscribe(new FlatMapMaybeObserver<>(downstream, mapper)); - } - - static final class FlatMapMaybeObserver - extends AtomicReference - implements MaybeObserver, Disposable { - - private static final long serialVersionUID = 4827726964688405508L; - - final MaybeObserver downstream; - - final Function> mapper; - - FlatMapMaybeObserver(MaybeObserver actual, Function> mapper) { - this.downstream = actual; - this.mapper = mapper; - } - - @Override - public void dispose() { - DisposableHelper.dispose(this); - } - - @Override - public boolean isDisposed() { - return DisposableHelper.isDisposed(get()); - } - - @Override - public void onSubscribe(Disposable d) { - if (DisposableHelper.setOnce(this, d)) { - downstream.onSubscribe(this); - } - } - - @Override - public void onSuccess(T value) { - SingleSource ss; - - try { - ss = Objects.requireNonNull(mapper.apply(value), "The mapper returned a null SingleSource"); - } catch (Throwable ex) { - Exceptions.throwIfFatal(ex); - onError(ex); - return; - } - - ss.subscribe(new FlatMapSingleObserver(this, downstream)); - } - - @Override - public void onError(Throwable e) { - downstream.onError(e); - } - - @Override - public void onComplete() { - downstream.onComplete(); - } - } - - static final class FlatMapSingleObserver implements SingleObserver { - - final AtomicReference parent; - - final MaybeObserver downstream; - - FlatMapSingleObserver(AtomicReference parent, MaybeObserver downstream) { - this.parent = parent; - this.downstream = downstream; - } - - @Override - public void onSubscribe(final Disposable d) { - DisposableHelper.replace(parent, d); - } - - @Override - public void onSuccess(final R value) { - downstream.onSuccess(value); - } - - @Override - public void onError(final Throwable e) { - downstream.onError(e); - } - } -} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten.java index 21d306095c8..485cf69ea1a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatten.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromAction.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromAction.java index 5bdf86f9047..3d9cf428cfa 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromAction.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromAction.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCallable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCallable.java index 088f2e14f02..592b02fad24 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCallable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCallable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCompletable.java index bdbc2ec03b7..f6ad406e356 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,7 +19,7 @@ import io.reactivex.rxjava3.internal.fuseable.HasUpstreamCompletableSource; /** - * Wrap a Single into a Maybe. + * Wrap a Completable into a Maybe. * * @param the value type */ diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromFuture.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromFuture.java index acc93b3ea62..e506a322659 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromFuture.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromFuture.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromRunnable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromRunnable.java index 4c83bbeee74..a102e4b9451 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromRunnable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromRunnable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSingle.java index c74a73ee25c..8fe691b7675 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSupplier.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSupplier.java index 38f0afdb62d..6eaf31ee641 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSupplier.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSupplier.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeHide.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeHide.java index 4dcddd0c276..2f87b5fddd1 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeHide.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeHide.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIgnoreElement.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIgnoreElement.java index 1c9242548d8..dcdbd2cd73b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIgnoreElement.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIgnoreElement.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIgnoreElementCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIgnoreElementCompletable.java index 6e9c1e9d679..42f40c92f1e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIgnoreElementCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIgnoreElementCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmpty.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmpty.java index 64fb3046ba7..a9642b92fe8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmpty.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmpty.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmptySingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmptySingle.java index a7fa1882b82..b4795a2985c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmptySingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmptySingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeJust.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeJust.java index 54dacb3c7d6..7e6fc6dfa67 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeJust.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeJust.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,7 +15,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.internal.fuseable.ScalarSupplier; +import io.reactivex.rxjava3.operators.ScalarSupplier; /** * Signals a constant value. diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeLift.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeLift.java index 8e40bbd45d2..a5a6d768777 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeLift.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeLift.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMap.java index 167e21d7fbb..2d637fdd432 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMaterialize.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMaterialize.java index 2690bc47976..022d92bbe89 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMaterialize.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMaterialize.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeArray.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeArray.java index e550b16fbac..82f6d62ddf8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeArray.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeArray.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,9 +22,9 @@ import io.reactivex.rxjava3.annotations.Nullable; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.*; -import io.reactivex.rxjava3.internal.fuseable.SimpleQueue; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimpleQueue; /** * Run all MaybeSources of an array at once and signal their values as they become available. diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeNever.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeNever.java index 9690c283598..a9c35c9b672 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeNever.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeNever.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn.java index 7bf03b080e6..5afb4beaf31 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeObserveOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorComplete.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorComplete.java index 8792a93cc5c..46c15bcb2a4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorComplete.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorComplete.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -37,10 +37,11 @@ public MaybeOnErrorComplete(MaybeSource source, @Override protected void subscribeActual(MaybeObserver observer) { - source.subscribe(new OnErrorCompleteMaybeObserver<>(observer, predicate)); + source.subscribe(new OnErrorCompleteMultiObserver<>(observer, predicate)); } - static final class OnErrorCompleteMaybeObserver implements MaybeObserver, Disposable { + public static final class OnErrorCompleteMultiObserver + implements MaybeObserver, SingleObserver, Disposable { final MaybeObserver downstream; @@ -48,7 +49,7 @@ static final class OnErrorCompleteMaybeObserver implements MaybeObserver, Disposable upstream; - OnErrorCompleteMaybeObserver(MaybeObserver actual, Predicate predicate) { + public OnErrorCompleteMultiObserver(MaybeObserver actual, Predicate predicate) { this.downstream = actual; this.predicate = predicate; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorNext.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorNext.java index 434685c074c..a3e975570da 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorNext.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorNext.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -31,19 +31,15 @@ public final class MaybeOnErrorNext extends AbstractMaybeWithUpstream { final Function> resumeFunction; - final boolean allowFatal; - public MaybeOnErrorNext(MaybeSource source, - Function> resumeFunction, - boolean allowFatal) { + Function> resumeFunction) { super(source); this.resumeFunction = resumeFunction; - this.allowFatal = allowFatal; } @Override protected void subscribeActual(MaybeObserver observer) { - source.subscribe(new OnErrorNextMaybeObserver<>(observer, resumeFunction, allowFatal)); + source.subscribe(new OnErrorNextMaybeObserver<>(observer, resumeFunction)); } static final class OnErrorNextMaybeObserver @@ -56,14 +52,10 @@ static final class OnErrorNextMaybeObserver final Function> resumeFunction; - final boolean allowFatal; - OnErrorNextMaybeObserver(MaybeObserver actual, - Function> resumeFunction, - boolean allowFatal) { + Function> resumeFunction) { this.downstream = actual; this.resumeFunction = resumeFunction; - this.allowFatal = allowFatal; } @Override @@ -90,10 +82,6 @@ public void onSuccess(T value) { @Override public void onError(Throwable e) { - if (!allowFatal && !(e instanceof Exception)) { - downstream.onError(e); - return; - } MaybeSource m; try { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorReturn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorReturn.java index 1a75120e84e..6d14b2c8cd7 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorReturn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorReturn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,31 +27,31 @@ */ public final class MaybeOnErrorReturn extends AbstractMaybeWithUpstream { - final Function valueSupplier; + final Function itemSupplier; public MaybeOnErrorReturn(MaybeSource source, - Function valueSupplier) { + Function itemSupplier) { super(source); - this.valueSupplier = valueSupplier; + this.itemSupplier = itemSupplier; } @Override protected void subscribeActual(MaybeObserver observer) { - source.subscribe(new OnErrorReturnMaybeObserver<>(observer, valueSupplier)); + source.subscribe(new OnErrorReturnMaybeObserver<>(observer, itemSupplier)); } static final class OnErrorReturnMaybeObserver implements MaybeObserver, Disposable { final MaybeObserver downstream; - final Function valueSupplier; + final Function itemSupplier; Disposable upstream; OnErrorReturnMaybeObserver(MaybeObserver actual, Function valueSupplier) { this.downstream = actual; - this.valueSupplier = valueSupplier; + this.itemSupplier = valueSupplier; } @Override @@ -83,7 +83,7 @@ public void onError(Throwable e) { T v; try { - v = Objects.requireNonNull(valueSupplier.apply(e), "The valueSupplier returned a null value"); + v = Objects.requireNonNull(itemSupplier.apply(e), "The itemSupplier returned a null value"); } catch (Throwable ex) { Exceptions.throwIfFatal(ex); downstream.onError(new CompositeException(e, ex)); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybePeek.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybePeek.java index 3b5427ba0fd..58c69839a1b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybePeek.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybePeek.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSubscribeOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSubscribeOn.java index 543b7c2b6ac..7ec1a6ad712 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSubscribeOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSubscribeOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmpty.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmpty.java index 3be260441c4..c432b3c6744 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmpty.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmpty.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmptySingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmptySingle.java index 142e39f1f67..29e77a3e56e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmptySingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmptySingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -124,4 +124,4 @@ public void onError(Throwable e) { } } -} \ No newline at end of file +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilMaybe.java index 6c9498c065d..e99011e509f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilPublisher.java index e86cc7c324c..8e57a5ee84a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeInterval.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeInterval.java new file mode 100644 index 00000000000..9580976d893 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeInterval.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.internal.disposables.DisposableHelper; +import io.reactivex.rxjava3.schedulers.Timed; + +/** + * Measures the time between subscription and the success item emission + * from the upstream and emits this as a {@link Timed} success value. + * @param the element type of the sequence + * @since 3.0.0 + */ +public final class MaybeTimeInterval extends Maybe> { + + final MaybeSource source; + + final TimeUnit unit; + + final Scheduler scheduler; + + final boolean start; + + public MaybeTimeInterval(MaybeSource source, TimeUnit unit, Scheduler scheduler, boolean start) { + this.source = source; + this.unit = unit; + this.scheduler = scheduler; + this.start = start; + } + + @Override + protected void subscribeActual(@NonNull MaybeObserver> observer) { + source.subscribe(new TimeIntervalMaybeObserver<>(observer, unit, scheduler, start)); + } + + static final class TimeIntervalMaybeObserver implements MaybeObserver, Disposable { + + final MaybeObserver> downstream; + + final TimeUnit unit; + + final Scheduler scheduler; + + final long startTime; + + Disposable upstream; + + TimeIntervalMaybeObserver(MaybeObserver> downstream, TimeUnit unit, Scheduler scheduler, boolean start) { + this.downstream = downstream; + this.unit = unit; + this.scheduler = scheduler; + this.startTime = start ? scheduler.now(unit) : 0L; + } + + @Override + public void onSubscribe(@NonNull Disposable d) { + if (DisposableHelper.validate(this.upstream, d)) { + this.upstream = d; + + downstream.onSubscribe(this); + } + } + + @Override + public void onSuccess(@NonNull T t) { + downstream.onSuccess(new Timed<>(t, scheduler.now(unit) - startTime, unit)); + } + + @Override + public void onError(@NonNull Throwable e) { + downstream.onError(e); + } + + @Override + public void onComplete() { + downstream.onComplete(); + } + + @Override + public void dispose() { + upstream.dispose(); + } + + @Override + public boolean isDisposed() { + return upstream.isDisposed(); + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutMaybe.java index 03783489a34..2a2581c5f3c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutPublisher.java index 76545730f31..e89a8d0bc96 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimer.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimer.java index a374c44ced0..2b9033c66b3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToFlowable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToFlowable.java index c31ad262abd..5ce9f661033 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToFlowable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToFlowable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToObservable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToObservable.java index 4b279186219..65ef0ced1b7 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToPublisher.java index 914021c9145..8f1f10d28d9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToSingle.java index 3199521639d..48ab0134e34 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ /** * Wraps a MaybeSource and exposes its onSuccess and onError signals and signals - * NoSuchElementException for onComplete. + * NoSuchElementException for onComplete if {@code defaultValue} is null. * * @param the value type */ diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUnsafeCreate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUnsafeCreate.java index 35621c1bbf0..462a2525b14 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUnsafeCreate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUnsafeCreate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUnsubscribeOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUnsubscribeOn.java index 2f07161dc92..b1d8cb6f65a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUnsubscribeOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUnsubscribeOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUsing.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUsing.java index 0e490d6f40f..74e4250e5fa 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUsing.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUsing.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipArray.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipArray.java index b155e019fc9..ac7514fb685 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipArray.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipArray.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -73,7 +73,7 @@ static final class ZipCoordinator extends AtomicInteger implements Disposa final ZipMaybeObserver[] observers; - final Object[] values; + Object[] values; @SuppressWarnings("unchecked") ZipCoordinator(MaybeObserver observer, int n, Function zipper) { @@ -99,11 +99,16 @@ public void dispose() { for (ZipMaybeObserver d : observers) { d.dispose(); } + + values = null; } } void innerSuccess(T value, int index) { - values[index] = value; + Object[] values = this.values; + if (values != null) { + values[index] = value; + } if (decrementAndGet() == 0) { R v; @@ -111,10 +116,12 @@ void innerSuccess(T value, int index) { v = Objects.requireNonNull(zipper.apply(values), "The zipper returned a null value"); } catch (Throwable ex) { Exceptions.throwIfFatal(ex); + this.values = null; downstream.onError(ex); return; } + this.values = null; downstream.onSuccess(v); } } @@ -133,6 +140,7 @@ void disposeExcept(int index) { void innerError(Throwable ex, int index) { if (getAndSet(0) > 0) { disposeExcept(index); + values = null; downstream.onError(ex); } else { RxJavaPlugins.onError(ex); @@ -142,6 +150,7 @@ void innerError(Throwable ex, int index) { void innerComplete(int index) { if (getAndSet(0) > 0) { disposeExcept(index); + values = null; downstream.onComplete(); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipIterable.java index 839b3739200..b247ca4ded5 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenObservable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenObservable.java index 2a3263a50a9..9f46c097f60 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenPublisher.java index c9017d0af6c..7004181bcc9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ConcatMapXMainObserver.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ConcatMapXMainObserver.java new file mode 100644 index 00000000000..d2d29b12135 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ConcatMapXMainObserver.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.mixed; + +import java.util.concurrent.atomic.AtomicInteger; + +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.internal.disposables.DisposableHelper; +import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; + +/** + * Base class for implementing concatMapX main observers. + * + * @param the upstream value type + * @since 3.0.10 + */ +public abstract class ConcatMapXMainObserver extends AtomicInteger +implements Observer, Disposable { + + private static final long serialVersionUID = -3214213361171757852L; + + final AtomicThrowable errors; + + final int prefetch; + + final ErrorMode errorMode; + + SimpleQueue queue; + + Disposable upstream; + + volatile boolean done; + + volatile boolean disposed; + + public ConcatMapXMainObserver(int prefetch, ErrorMode errorMode) { + this.errorMode = errorMode; + this.errors = new AtomicThrowable(); + this.prefetch = prefetch; + } + + @Override + public final void onSubscribe(Disposable d) { + if (DisposableHelper.validate(upstream, d)) { + upstream = d; + if (d instanceof QueueDisposable) { + @SuppressWarnings("unchecked") + QueueDisposable qd = (QueueDisposable)d; + int mode = qd.requestFusion(QueueFuseable.ANY | QueueFuseable.BOUNDARY); + if (mode == QueueFuseable.SYNC) { + queue = qd; + done = true; + + onSubscribeDownstream(); + + drain(); + return; + } + else if (mode == QueueFuseable.ASYNC) { + queue = qd; + + onSubscribeDownstream(); + + return; + } + } + + queue = new SpscLinkedArrayQueue<>(prefetch); + onSubscribeDownstream(); + } + } + + @Override + public final void onNext(T t) { + // In async fusion mode, t is a drain indicator + if (t != null) { + queue.offer(t); + } + drain(); + } + + @Override + public final void onError(Throwable t) { + if (errors.tryAddThrowableOrReport(t)) { + if (errorMode == ErrorMode.IMMEDIATE) { + disposeInner(); + } + done = true; + drain(); + } + } + + @Override + public final void onComplete() { + done = true; + drain(); + } + + @Override + public final void dispose() { + disposed = true; + upstream.dispose(); + disposeInner(); + errors.tryTerminateAndReport(); + if (getAndIncrement() == 0) { + queue.clear(); + clearValue(); + } + } + + @Override + public final boolean isDisposed() { + return disposed; + } + + /** + * Override this to clear values when the downstream disposes. + */ + void clearValue() { + } + + /** + * Typically, this should be {@code downstream.onSubscribe(this)}. + */ + abstract void onSubscribeDownstream(); + + /** + * Typically, this should be {@code inner.dispose()}. + */ + abstract void disposeInner(); + + /** + * Implement the serialized inner subscribing and value emission here. + */ + abstract void drain(); +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ConcatMapXMainSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ConcatMapXMainSubscriber.java new file mode 100644 index 00000000000..03e4c568d69 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ConcatMapXMainSubscriber.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.mixed; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.reactivestreams.Subscription; + +import io.reactivex.rxjava3.core.FlowableSubscriber; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; + +/** + * Base class for implementing concatMapX main subscribers. + * + * @param the upstream value type + * @since 3.0.10 + */ +public abstract class ConcatMapXMainSubscriber extends AtomicInteger +implements FlowableSubscriber { + + private static final long serialVersionUID = -3214213361171757852L; + + final AtomicThrowable errors; + + final int prefetch; + + final ErrorMode errorMode; + + SimpleQueue queue; + + Subscription upstream; + + volatile boolean done; + + volatile boolean cancelled; + + boolean syncFused; + + public ConcatMapXMainSubscriber(int prefetch, ErrorMode errorMode) { + this.errorMode = errorMode; + this.errors = new AtomicThrowable(); + this.prefetch = prefetch; + } + + @Override + public final void onSubscribe(Subscription s) { + if (SubscriptionHelper.validate(upstream, s)) { + upstream = s; + if (s instanceof QueueSubscription) { + @SuppressWarnings("unchecked") + QueueSubscription qs = (QueueSubscription)s; + int mode = qs.requestFusion(QueueFuseable.ANY | QueueFuseable.BOUNDARY); + if (mode == QueueFuseable.SYNC) { + queue = qs; + syncFused = true; + done = true; + + onSubscribeDownstream(); + + drain(); + return; + } + else if (mode == QueueFuseable.ASYNC) { + queue = qs; + + onSubscribeDownstream(); + + upstream.request(prefetch); + return; + } + } + + queue = new SpscArrayQueue<>(prefetch); + onSubscribeDownstream(); + upstream.request(prefetch); + } + } + + @Override + public final void onNext(T t) { + // In async fusion mode, t is a drain indicator + if (t != null) { + if (!queue.offer(t)) { + upstream.cancel(); + onError(new QueueOverflowException()); + return; + } + } + drain(); + } + + @Override + public final void onError(Throwable t) { + if (errors.tryAddThrowableOrReport(t)) { + if (errorMode == ErrorMode.IMMEDIATE) { + disposeInner(); + } + done = true; + drain(); + } + } + + @Override + public final void onComplete() { + done = true; + drain(); + } + + final void stop() { + cancelled = true; + upstream.cancel(); + disposeInner(); + errors.tryTerminateAndReport(); + if (getAndIncrement() == 0) { + queue.clear(); + clearValue(); + } + } + + /** + * Override this to clear values when the downstream disposes. + */ + void clearValue() { + } + + /** + * Typically, this should be {@code downstream.onSubscribe(this);}. + */ + abstract void onSubscribeDownstream(); + + /** + * Typically, this should be {@code inner.dispose()}. + */ + abstract void disposeInner(); + + /** + * Implement the serialized inner subscribing and value emission here. + */ + abstract void drain(); +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapCompletable.java index e4a3f36c054..ab93e4c27ff 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,19 +14,15 @@ package io.reactivex.rxjava3.internal.operators.mixed; import java.util.Objects; -import java.util.concurrent.atomic.*; - -import org.reactivestreams.Subscription; +import java.util.concurrent.atomic.AtomicReference; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; -import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimpleQueue; /** * Maps the upstream items into {@link CompletableSource}s and subscribes to them one after the @@ -61,8 +57,8 @@ protected void subscribeActual(CompletableObserver observer) { } static final class ConcatMapCompletableObserver - extends AtomicInteger - implements FlowableSubscriber, Disposable { + extends ConcatMapXMainSubscriber + implements Disposable { private static final long serialVersionUID = 3610901111000061034L; @@ -70,93 +66,39 @@ static final class ConcatMapCompletableObserver final Function mapper; - final ErrorMode errorMode; - - final AtomicThrowable errors; - final ConcatMapInnerObserver inner; - final int prefetch; - - final SimplePlainQueue queue; - - Subscription upstream; - volatile boolean active; - volatile boolean done; - - volatile boolean disposed; - int consumed; ConcatMapCompletableObserver(CompletableObserver downstream, Function mapper, ErrorMode errorMode, int prefetch) { + super(prefetch, errorMode); this.downstream = downstream; this.mapper = mapper; - this.errorMode = errorMode; - this.prefetch = prefetch; - this.errors = new AtomicThrowable(); this.inner = new ConcatMapInnerObserver(this); - this.queue = new SpscArrayQueue<>(prefetch); - } - - @Override - public void onSubscribe(Subscription s) { - if (SubscriptionHelper.validate(upstream, s)) { - this.upstream = s; - downstream.onSubscribe(this); - s.request(prefetch); - } - } - - @Override - public void onNext(T t) { - if (queue.offer(t)) { - drain(); - } else { - upstream.cancel(); - onError(new MissingBackpressureException("Queue full?!")); - } } @Override - public void onError(Throwable t) { - if (errors.tryAddThrowableOrReport(t)) { - if (errorMode == ErrorMode.IMMEDIATE) { - inner.dispose(); - errors.tryTerminateConsumer(downstream); - if (getAndIncrement() == 0) { - queue.clear(); - } - } else { - done = true; - drain(); - } - } + void onSubscribeDownstream() { + downstream.onSubscribe(this); } @Override - public void onComplete() { - done = true; - drain(); + void disposeInner() { + inner.dispose(); } @Override public void dispose() { - disposed = true; - upstream.cancel(); - inner.dispose(); - errors.tryTerminateAndReport(); - if (getAndIncrement() == 0) { - queue.clear(); - } + stop(); } @Override public boolean isDisposed() { - return disposed; + return cancelled; } void innerError(Throwable ex) { @@ -179,29 +121,45 @@ void innerComplete() { drain(); } + @Override void drain() { if (getAndIncrement() != 0) { return; } + ErrorMode errorMode = this.errorMode; + SimpleQueue queue = this.queue; + AtomicThrowable errors = this.errors; + boolean syncFused = this.syncFused; + do { - if (disposed) { + if (cancelled) { queue.clear(); return; } - if (!active) { - - if (errorMode == ErrorMode.BOUNDARY) { - if (errors.get() != null) { - queue.clear(); - errors.tryTerminateConsumer(downstream); - return; - } + if (errors.get() != null) { + if (errorMode == ErrorMode.IMMEDIATE + || (errorMode == ErrorMode.BOUNDARY && !active)) { + queue.clear(); + errors.tryTerminateConsumer(downstream); + return; } + } + + if (!active) { boolean d = done; - T v = queue.poll(); + T v; + try { + v = queue.poll(); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.cancel(); + errors.tryAddThrowableOrReport(ex); + errors.tryTerminateConsumer(downstream); + return; + } boolean empty = v == null; if (d && empty) { @@ -212,12 +170,15 @@ void drain() { if (!empty) { int limit = prefetch - (prefetch >> 1); - int c = consumed + 1; - if (c == limit) { - consumed = 0; - upstream.request(limit); - } else { - consumed = c; + + if (!syncFused) { + int c = consumed + 1; + if (c == limit) { + consumed = 0; + upstream.request(limit); + } else { + consumed = c; + } } CompletableSource cs; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapMaybe.java index 5f71148e0d6..944ac69311c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,13 +20,11 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; -import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimpleQueue; /** * Maps each upstream item into a {@link MaybeSource}, subscribes to them one after the other terminates @@ -62,8 +60,7 @@ protected void subscribeActual(Subscriber s) { } static final class ConcatMapMaybeSubscriber - extends AtomicInteger - implements FlowableSubscriber, Subscription { + extends ConcatMapXMainSubscriber implements Subscription { private static final long serialVersionUID = -9140123220065488293L; @@ -71,24 +68,10 @@ static final class ConcatMapMaybeSubscriber final Function> mapper; - final int prefetch; - final AtomicLong requested; - final AtomicThrowable errors; - final ConcatMapMaybeObserver inner; - final SimplePlainQueue queue; - - final ErrorMode errorMode; - - Subscription upstream; - - volatile boolean done; - - volatile boolean cancelled; - long emitted; int consumed; @@ -107,50 +90,16 @@ static final class ConcatMapMaybeSubscriber ConcatMapMaybeSubscriber(Subscriber downstream, Function> mapper, int prefetch, ErrorMode errorMode) { + super(prefetch, errorMode); this.downstream = downstream; this.mapper = mapper; - this.prefetch = prefetch; - this.errorMode = errorMode; this.requested = new AtomicLong(); - this.errors = new AtomicThrowable(); this.inner = new ConcatMapMaybeObserver<>(this); - this.queue = new SpscArrayQueue<>(prefetch); - } - - @Override - public void onSubscribe(Subscription s) { - if (SubscriptionHelper.validate(upstream, s)) { - upstream = s; - downstream.onSubscribe(this); - s.request(prefetch); - } - } - - @Override - public void onNext(T t) { - if (!queue.offer(t)) { - upstream.cancel(); - onError(new MissingBackpressureException("queue full?!")); - return; - } - drain(); - } - - @Override - public void onError(Throwable t) { - if (errors.tryAddThrowableOrReport(t)) { - if (errorMode == ErrorMode.IMMEDIATE) { - inner.dispose(); - } - done = true; - drain(); - } } @Override - public void onComplete() { - done = true; - drain(); + void onSubscribeDownstream() { + downstream.onSubscribe(this); } @Override @@ -161,14 +110,7 @@ public void request(long n) { @Override public void cancel() { - cancelled = true; - upstream.cancel(); - inner.dispose(); - errors.tryTerminateAndReport(); - if (getAndIncrement() == 0) { - queue.clear(); - item = null; - } + stop(); } void innerSuccess(R item) { @@ -192,6 +134,17 @@ void innerError(Throwable ex) { } } + @Override + void clearValue() { + item = null; + } + + @Override + void disposeInner() { + inner.dispose(); + } + + @Override void drain() { if (getAndIncrement() != 0) { return; @@ -200,10 +153,11 @@ void drain() { int missed = 1; Subscriber downstream = this.downstream; ErrorMode errorMode = this.errorMode; - SimplePlainQueue queue = this.queue; + SimpleQueue queue = this.queue; AtomicThrowable errors = this.errors; AtomicLong requested = this.requested; int limit = prefetch - (prefetch >> 1); + boolean syncFused = this.syncFused; for (;;) { @@ -228,7 +182,16 @@ void drain() { if (s == STATE_INACTIVE) { boolean d = done; - T v = queue.poll(); + T v; + try { + v = queue.poll(); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.cancel(); + errors.tryAddThrowableOrReport(ex); + errors.tryTerminateConsumer(downstream); + return; + } boolean empty = v == null; if (d && empty) { @@ -240,12 +203,14 @@ void drain() { break; } - int c = consumed + 1; - if (c == limit) { - consumed = 0; - upstream.request(limit); - } else { - consumed = c; + if (!syncFused) { + int c = consumed + 1; + if (c == limit) { + consumed = 0; + upstream.request(limit); + } else { + consumed = c; + } } MaybeSource ms; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapMaybePublisher.java similarity index 51% rename from src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapPublisher.java rename to src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapMaybePublisher.java index 8ee6afcd873..42c1f732c20 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapMaybePublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,40 +10,46 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ -package io.reactivex.rxjava3.internal.operators.flowable; + +package io.reactivex.rxjava3.internal.operators.mixed; import org.reactivestreams.*; -import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.internal.operators.mixed.FlowableConcatMapMaybe.ConcatMapMaybeSubscriber; import io.reactivex.rxjava3.internal.util.ErrorMode; -public final class FlowableConcatMapPublisher extends Flowable { +/** + * Maps each upstream item into a {@link MaybeSource}, subscribes to them one after the other terminates + * and relays their success values, optionally delaying any errors till the main and inner sources + * terminate. + *

History: 2.1.11 - experimental + * @param the upstream element type + * @param the output element type + * @since 2.2 + */ +public final class FlowableConcatMapMaybePublisher extends Flowable { final Publisher source; - final Function> mapper; - - final int prefetch; + final Function> mapper; final ErrorMode errorMode; - public FlowableConcatMapPublisher(Publisher source, - Function> mapper, - int prefetch, ErrorMode errorMode) { + final int prefetch; + + public FlowableConcatMapMaybePublisher(Publisher source, + Function> mapper, + ErrorMode errorMode, int prefetch) { this.source = source; this.mapper = mapper; - this.prefetch = prefetch; this.errorMode = errorMode; + this.prefetch = prefetch; } @Override protected void subscribeActual(Subscriber s) { - - if (FlowableScalarXMap.tryScalarXMapSubscribe(source, s, mapper)) { - return; - } - - source.subscribe(FlowableConcatMap.subscribe(s, mapper, prefetch, errorMode)); + source.subscribe(new ConcatMapMaybeSubscriber<>(s, mapper, prefetch, errorMode)); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapSingle.java index f6cd9395462..5c18b6b2587 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,13 +20,11 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; -import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimpleQueue; /** * Maps each upstream item into a {@link SingleSource}, subscribes to them one after the other terminates @@ -62,8 +60,7 @@ protected void subscribeActual(Subscriber s) { } static final class ConcatMapSingleSubscriber - extends AtomicInteger - implements FlowableSubscriber, Subscription { + extends ConcatMapXMainSubscriber implements Subscription { private static final long serialVersionUID = -9140123220065488293L; @@ -71,24 +68,10 @@ static final class ConcatMapSingleSubscriber final Function> mapper; - final int prefetch; - final AtomicLong requested; - final AtomicThrowable errors; - final ConcatMapSingleObserver inner; - final SimplePlainQueue queue; - - final ErrorMode errorMode; - - Subscription upstream; - - volatile boolean done; - - volatile boolean cancelled; - long emitted; int consumed; @@ -107,68 +90,37 @@ static final class ConcatMapSingleSubscriber ConcatMapSingleSubscriber(Subscriber downstream, Function> mapper, int prefetch, ErrorMode errorMode) { + super(prefetch, errorMode); this.downstream = downstream; this.mapper = mapper; - this.prefetch = prefetch; - this.errorMode = errorMode; this.requested = new AtomicLong(); - this.errors = new AtomicThrowable(); this.inner = new ConcatMapSingleObserver<>(this); - this.queue = new SpscArrayQueue<>(prefetch); } @Override - public void onSubscribe(Subscription s) { - if (SubscriptionHelper.validate(upstream, s)) { - upstream = s; - downstream.onSubscribe(this); - s.request(prefetch); - } + void onSubscribeDownstream() { + downstream.onSubscribe(this); } @Override - public void onNext(T t) { - if (!queue.offer(t)) { - upstream.cancel(); - onError(new MissingBackpressureException("queue full?!")); - return; - } + public void request(long n) { + BackpressureHelper.add(requested, n); drain(); } @Override - public void onError(Throwable t) { - if (errors.tryAddThrowableOrReport(t)) { - if (errorMode == ErrorMode.IMMEDIATE) { - inner.dispose(); - } - done = true; - drain(); - } - } - - @Override - public void onComplete() { - done = true; - drain(); + public void cancel() { + stop(); } @Override - public void request(long n) { - BackpressureHelper.add(requested, n); - drain(); + void clearValue() { + item = null; } @Override - public void cancel() { - cancelled = true; - upstream.cancel(); + void disposeInner() { inner.dispose(); - errors.tryTerminateAndReport(); - if (getAndIncrement() == 0) { - queue.clear(); - item = null; - } } void innerSuccess(R item) { @@ -187,6 +139,7 @@ void innerError(Throwable ex) { } } + @Override void drain() { if (getAndIncrement() != 0) { return; @@ -195,10 +148,11 @@ void drain() { int missed = 1; Subscriber downstream = this.downstream; ErrorMode errorMode = this.errorMode; - SimplePlainQueue queue = this.queue; + SimpleQueue queue = this.queue; AtomicThrowable errors = this.errors; AtomicLong requested = this.requested; int limit = prefetch - (prefetch >> 1); + boolean syncFused = this.syncFused; for (;;) { @@ -223,7 +177,16 @@ void drain() { if (s == STATE_INACTIVE) { boolean d = done; - T v = queue.poll(); + T v; + try { + v = queue.poll(); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.cancel(); + errors.tryAddThrowableOrReport(ex); + errors.tryTerminateConsumer(downstream); + return; + } boolean empty = v == null; if (d && empty) { @@ -235,12 +198,14 @@ void drain() { break; } - int c = consumed + 1; - if (c == limit) { - consumed = 0; - upstream.request(limit); - } else { - consumed = c; + if (!syncFused) { + int c = consumed + 1; + if (c == limit) { + consumed = 0; + upstream.request(limit); + } else { + consumed = c; + } } SingleSource ss; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapSinglePublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapSinglePublisher.java new file mode 100644 index 00000000000..0e1986180a9 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapSinglePublisher.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.mixed; + +import org.reactivestreams.*; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.internal.operators.mixed.FlowableConcatMapSingle.ConcatMapSingleSubscriber; +import io.reactivex.rxjava3.internal.util.ErrorMode; + +/** + * Maps each upstream item into a {@link SingleSource}, subscribes to them one after the other terminates + * and relays their success values, optionally delaying any errors till the main and inner sources + * terminate. + *

History: 2.1.11 - experimental + * @param the upstream element type + * @param the output element type + * @since 2.2 + */ +public final class FlowableConcatMapSinglePublisher extends Flowable { + + final Publisher source; + + final Function> mapper; + + final ErrorMode errorMode; + + final int prefetch; + + public FlowableConcatMapSinglePublisher(Publisher source, + Function> mapper, + ErrorMode errorMode, int prefetch) { + this.source = source; + this.mapper = mapper; + this.errorMode = errorMode; + this.prefetch = prefetch; + } + + @Override + protected void subscribeActual(Subscriber s) { + source.subscribe(new ConcatMapSingleSubscriber<>(s, mapper, prefetch, errorMode)); + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapCompletable.java index 1bc0fb709e8..9ca61ab15a2 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapCompletablePublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapCompletablePublisher.java new file mode 100644 index 00000000000..9eae52029e8 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapCompletablePublisher.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.mixed; + +import org.reactivestreams.Publisher; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.functions.Function; + +/** + * Switch between subsequent {@link CompletableSource}s emitted by a {@link Publisher}. + * Reuses {@link FlowableSwitchMapCompletable} internals. + * @param the upstream value type + * @since 3.0.0 + */ +public final class FlowableSwitchMapCompletablePublisher extends Completable { + + final Publisher source; + + final Function mapper; + + final boolean delayErrors; + + public FlowableSwitchMapCompletablePublisher(Publisher source, + Function mapper, boolean delayErrors) { + this.source = source; + this.mapper = mapper; + this.delayErrors = delayErrors; + } + + @Override + protected void subscribeActual(CompletableObserver observer) { + source.subscribe(new FlowableSwitchMapCompletable.SwitchMapCompletableObserver<>(observer, mapper, delayErrors)); + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapMaybe.java index 7933b4ec139..3eab4e0d622 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapMaybePublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapMaybePublisher.java new file mode 100644 index 00000000000..319247c2952 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapMaybePublisher.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.mixed; + +import org.reactivestreams.*; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.functions.Function; + +/** + * Switch between subsequent {@link MaybeSource}s emitted by a {@link Publisher}. + * Reuses {@link FlowableSwitchMapMaybe} internals. + * @param the upstream value type + * @param the downstream value type + * @since 3.0.0 + */ +public final class FlowableSwitchMapMaybePublisher extends Flowable { + + final Publisher source; + + final Function> mapper; + + final boolean delayErrors; + + public FlowableSwitchMapMaybePublisher(Publisher source, + Function> mapper, + boolean delayErrors) { + this.source = source; + this.mapper = mapper; + this.delayErrors = delayErrors; + } + + @Override + protected void subscribeActual(Subscriber s) { + source.subscribe(new FlowableSwitchMapMaybe.SwitchMapMaybeSubscriber<>(s, mapper, delayErrors)); + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle.java index 4fe83126e55..59c9cb7f8f7 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSinglePublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSinglePublisher.java new file mode 100644 index 00000000000..31ace1bf2dc --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSinglePublisher.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.mixed; + +import org.reactivestreams.*; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.functions.Function; + +/** + * Switch between subsequent {@link SingleSource}s emitted by a {@link Publisher}. + * Reuses {@link FlowableSwitchMapSingle} internals. + * @param the upstream value type + * @param the downstream value type + * @since 3.0.0 + */ +public final class FlowableSwitchMapSinglePublisher extends Flowable { + + final Publisher source; + + final Function> mapper; + + final boolean delayErrors; + + public FlowableSwitchMapSinglePublisher(Publisher source, + Function> mapper, + boolean delayErrors) { + this.source = source; + this.mapper = mapper; + this.delayErrors = delayErrors; + } + + @Override + protected void subscribeActual(Subscriber s) { + source.subscribe(new FlowableSwitchMapSingle.SwitchMapSingleSubscriber<>(s, mapper, delayErrors)); + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/MaterializeSingleObserver.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/MaterializeSingleObserver.java index d9cb5592ac9..3f1c540d7df 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/MaterializeSingleObserver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/MaterializeSingleObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapObservable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapObservable.java index ae42405f74c..09e634f944a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -106,7 +106,9 @@ public void onSuccess(T t) { return; } - o.subscribe(this); + if (!isDisposed()) { + o.subscribe(this); + } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapPublisher.java index c590755704e..b6d2afeb2d0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -116,7 +116,9 @@ public void onSuccess(T t) { return; } - p.subscribe(this); + if (get() != SubscriptionHelper.CANCELLED) { + p.subscribe(this); + } } @Override diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapCompletable.java index 2295f4397ed..f9d91b170a6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,16 +14,15 @@ package io.reactivex.rxjava3.internal.operators.mixed; import java.util.Objects; -import java.util.concurrent.atomic.*; +import java.util.concurrent.atomic.AtomicReference; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimpleQueue; /** * Maps the upstream items into {@link CompletableSource}s and subscribes to them one after the @@ -60,8 +59,7 @@ protected void subscribeActual(CompletableObserver observer) { } static final class ConcatMapCompletableObserver - extends AtomicInteger - implements Observer, Disposable { + extends ConcatMapXMainObserver { private static final long serialVersionUID = 3610901111000061034L; @@ -69,122 +67,36 @@ static final class ConcatMapCompletableObserver final Function mapper; - final ErrorMode errorMode; - - final AtomicThrowable errors; - final ConcatMapInnerObserver inner; - final int prefetch; - - SimpleQueue queue; - - Disposable upstream; - volatile boolean active; - volatile boolean done; - - volatile boolean disposed; - ConcatMapCompletableObserver(CompletableObserver downstream, Function mapper, ErrorMode errorMode, int prefetch) { + super(prefetch, errorMode); this.downstream = downstream; this.mapper = mapper; - this.errorMode = errorMode; - this.prefetch = prefetch; - this.errors = new AtomicThrowable(); this.inner = new ConcatMapInnerObserver(this); } @Override - public void onSubscribe(Disposable d) { - if (DisposableHelper.validate(upstream, d)) { - this.upstream = d; - if (d instanceof QueueDisposable) { - @SuppressWarnings("unchecked") - QueueDisposable qd = (QueueDisposable) d; - - int m = qd.requestFusion(QueueDisposable.ANY); - if (m == QueueDisposable.SYNC) { - queue = qd; - done = true; - downstream.onSubscribe(this); - drain(); - return; - } - if (m == QueueDisposable.ASYNC) { - queue = qd; - downstream.onSubscribe(this); - return; - } - } - queue = new SpscLinkedArrayQueue<>(prefetch); - downstream.onSubscribe(this); - } - } - - @Override - public void onNext(T t) { - if (t != null) { - queue.offer(t); - } - drain(); + void onSubscribeDownstream() { + downstream.onSubscribe(this); } @Override - public void onError(Throwable t) { - if (errors.tryAddThrowableOrReport(t)) { - if (errorMode == ErrorMode.IMMEDIATE) { - disposed = true; - inner.dispose(); - errors.tryTerminateConsumer(downstream); - if (getAndIncrement() == 0) { - queue.clear(); - } - } else { - done = true; - drain(); - } - } - } - - @Override - public void onComplete() { - done = true; - drain(); - } - - @Override - public void dispose() { - disposed = true; - upstream.dispose(); + void disposeInner() { inner.dispose(); - errors.tryTerminateAndReport(); - if (getAndIncrement() == 0) { - queue.clear(); - } - } - - @Override - public boolean isDisposed() { - return disposed; } void innerError(Throwable ex) { if (errors.tryAddThrowableOrReport(ex)) { - if (errorMode == ErrorMode.IMMEDIATE) { - disposed = true; + if (errorMode != ErrorMode.END) { upstream.dispose(); - errors.tryTerminateConsumer(downstream); - if (getAndIncrement() == 0) { - queue.clear(); - } - } else { - active = false; - drain(); } + active = false; + drain(); } } @@ -193,6 +105,7 @@ void innerComplete() { drain(); } + @Override void drain() { if (getAndIncrement() != 0) { return; @@ -200,6 +113,7 @@ void drain() { AtomicThrowable errors = this.errors; ErrorMode errorMode = this.errorMode; + SimpleQueue queue = this.queue; do { if (disposed) { @@ -207,16 +121,17 @@ void drain() { return; } - if (!active) { - - if (errorMode == ErrorMode.BOUNDARY) { - if (errors.get() != null) { - disposed = true; - queue.clear(); - errors.tryTerminateConsumer(downstream); - return; - } + if (errors.get() != null) { + if (errorMode == ErrorMode.IMMEDIATE + || (errorMode == ErrorMode.BOUNDARY && !active)) { + disposed = true; + queue.clear(); + errors.tryTerminateConsumer(downstream); + return; } + } + + if (!active) { boolean d = done; boolean empty = true; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapMaybe.java index 1177d5a06e6..7e85104dd7b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,16 +14,15 @@ package io.reactivex.rxjava3.internal.operators.mixed; import java.util.Objects; -import java.util.concurrent.atomic.*; +import java.util.concurrent.atomic.AtomicReference; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimpleQueue; /** * Maps each upstream item into a {@link MaybeSource}, subscribes to them one after the other terminates @@ -61,8 +60,7 @@ protected void subscribeActual(Observer observer) { } static final class ConcatMapMaybeMainObserver - extends AtomicInteger - implements Observer, Disposable { + extends ConcatMapXMainObserver { private static final long serialVersionUID = -9140123220065488293L; @@ -70,20 +68,8 @@ static final class ConcatMapMaybeMainObserver final Function> mapper; - final AtomicThrowable errors; - final ConcatMapMaybeObserver inner; - final SimplePlainQueue queue; - - final ErrorMode errorMode; - - Disposable upstream; - - volatile boolean done; - - volatile boolean cancelled; - R item; volatile int state; @@ -98,60 +84,20 @@ static final class ConcatMapMaybeMainObserver ConcatMapMaybeMainObserver(Observer downstream, Function> mapper, int prefetch, ErrorMode errorMode) { + super(prefetch, errorMode); this.downstream = downstream; this.mapper = mapper; - this.errorMode = errorMode; - this.errors = new AtomicThrowable(); this.inner = new ConcatMapMaybeObserver<>(this); - this.queue = new SpscLinkedArrayQueue<>(prefetch); } @Override - public void onSubscribe(Disposable d) { - if (DisposableHelper.validate(upstream, d)) { - upstream = d; - downstream.onSubscribe(this); - } + void onSubscribeDownstream() { + downstream.onSubscribe(this); } @Override - public void onNext(T t) { - queue.offer(t); - drain(); - } - - @Override - public void onError(Throwable t) { - if (errors.tryAddThrowableOrReport(t)) { - if (errorMode == ErrorMode.IMMEDIATE) { - inner.dispose(); - } - done = true; - drain(); - } - } - - @Override - public void onComplete() { - done = true; - drain(); - } - - @Override - public void dispose() { - cancelled = true; - upstream.dispose(); - inner.dispose(); - errors.tryTerminateAndReport(); - if (getAndIncrement() == 0) { - queue.clear(); - item = null; - } - } - - @Override - public boolean isDisposed() { - return cancelled; + void clearValue() { + item = null; } void innerSuccess(R item) { @@ -175,6 +121,12 @@ void innerError(Throwable ex) { } } + @Override + void disposeInner() { + inner.dispose(); + } + + @Override void drain() { if (getAndIncrement() != 0) { return; @@ -183,13 +135,13 @@ void drain() { int missed = 1; Observer downstream = this.downstream; ErrorMode errorMode = this.errorMode; - SimplePlainQueue queue = this.queue; + SimpleQueue queue = this.queue; AtomicThrowable errors = this.errors; for (;;) { for (;;) { - if (cancelled) { + if (disposed) { queue.clear(); item = null; break; @@ -209,7 +161,18 @@ void drain() { if (s == STATE_INACTIVE) { boolean d = done; - T v = queue.poll(); + T v; + + try { + v = queue.poll(); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + disposed = true; + upstream.dispose(); + errors.tryAddThrowableOrReport(ex); + errors.tryTerminateConsumer(downstream); + return; + } boolean empty = v == null; if (d && empty) { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapSingle.java index 5fc6b8a5204..b57940a5e7c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,16 +14,15 @@ package io.reactivex.rxjava3.internal.operators.mixed; import java.util.Objects; -import java.util.concurrent.atomic.*; +import java.util.concurrent.atomic.AtomicReference; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimpleQueue; /** * Maps each upstream item into a {@link SingleSource}, subscribes to them one after the other terminates @@ -36,7 +35,7 @@ */ public final class ObservableConcatMapSingle extends Observable { - final Observable source; + final ObservableSource source; final Function> mapper; @@ -44,7 +43,7 @@ public final class ObservableConcatMapSingle extends Observable { final int prefetch; - public ObservableConcatMapSingle(Observable source, + public ObservableConcatMapSingle(ObservableSource source, Function> mapper, ErrorMode errorMode, int prefetch) { this.source = source; @@ -61,8 +60,7 @@ protected void subscribeActual(Observer observer) { } static final class ConcatMapSingleMainObserver - extends AtomicInteger - implements Observer, Disposable { + extends ConcatMapXMainObserver { private static final long serialVersionUID = -9140123220065488293L; @@ -70,20 +68,8 @@ static final class ConcatMapSingleMainObserver final Function> mapper; - final AtomicThrowable errors; - final ConcatMapSingleObserver inner; - final SimplePlainQueue queue; - - final ErrorMode errorMode; - - Disposable upstream; - - volatile boolean done; - - volatile boolean cancelled; - R item; volatile int state; @@ -98,78 +84,44 @@ static final class ConcatMapSingleMainObserver ConcatMapSingleMainObserver(Observer downstream, Function> mapper, int prefetch, ErrorMode errorMode) { + super(prefetch, errorMode); this.downstream = downstream; this.mapper = mapper; - this.errorMode = errorMode; - this.errors = new AtomicThrowable(); this.inner = new ConcatMapSingleObserver<>(this); - this.queue = new SpscLinkedArrayQueue<>(prefetch); } - @Override - public void onSubscribe(Disposable d) { - if (DisposableHelper.validate(upstream, d)) { - upstream = d; - downstream.onSubscribe(this); - } - } - - @Override - public void onNext(T t) { - queue.offer(t); + void innerSuccess(R item) { + this.item = item; + this.state = STATE_RESULT_VALUE; drain(); } - @Override - public void onError(Throwable t) { - if (errors.tryAddThrowableOrReport(t)) { - if (errorMode == ErrorMode.IMMEDIATE) { - inner.dispose(); + void innerError(Throwable ex) { + if (errors.tryAddThrowableOrReport(ex)) { + if (errorMode != ErrorMode.END) { + upstream.dispose(); } - done = true; + this.state = STATE_INACTIVE; drain(); } } @Override - public void onComplete() { - done = true; - drain(); - } - - @Override - public void dispose() { - cancelled = true; - upstream.dispose(); + void disposeInner() { inner.dispose(); - errors.tryTerminateAndReport(); - if (getAndIncrement() == 0) { - queue.clear(); - item = null; - } } @Override - public boolean isDisposed() { - return cancelled; + void onSubscribeDownstream() { + downstream.onSubscribe(this); } - void innerSuccess(R item) { - this.item = item; - this.state = STATE_RESULT_VALUE; - drain(); - } - - void innerError(Throwable ex) { - if (errors.tryAddThrowableOrReport(ex)) { - if (errorMode != ErrorMode.END) { - upstream.dispose(); - } - this.state = STATE_INACTIVE; - drain(); - } + @Override + void clearValue() { + item = null; } + @Override void drain() { if (getAndIncrement() != 0) { return; @@ -178,13 +130,13 @@ void drain() { int missed = 1; Observer downstream = this.downstream; ErrorMode errorMode = this.errorMode; - SimplePlainQueue queue = this.queue; + SimpleQueue queue = this.queue; AtomicThrowable errors = this.errors; for (;;) { for (;;) { - if (cancelled) { + if (disposed) { queue.clear(); item = null; break; @@ -204,7 +156,18 @@ void drain() { if (s == STATE_INACTIVE) { boolean d = done; - T v = queue.poll(); + T v; + + try { + v = queue.poll(); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + disposed = true; + upstream.dispose(); + errors.tryAddThrowableOrReport(ex); + errors.tryTerminateConsumer(downstream); + return; + } boolean empty = v == null; if (d && empty) { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapCompletable.java index bb6ec70f850..b751afdbb0a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapMaybe.java index f4c9bf6c0c8..fe394df1e8d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingle.java index f5db39d5d58..ca0e2953e05 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ScalarXMapZHelper.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ScalarXMapZHelper.java index d7fe0e34458..2ed6301e42d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ScalarXMapZHelper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/ScalarXMapZHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -78,6 +78,7 @@ static boolean tryAsCompletable(Object source, * Try subscribing to a {@link MaybeSource} mapped from * a scalar source (which implements {@link Supplier}). * @param the upstream value type + * @param the downstream value type * @param source the source reactive type ({@code Flowable} or {@code Observable}) * possibly implementing {@link Supplier}. * @param mapper the function that turns the scalar upstream value into a @@ -117,6 +118,7 @@ static boolean tryAsMaybe(Object source, * Try subscribing to a {@link SingleSource} mapped from * a scalar source (which implements {@link Supplier}). * @param the upstream value type + * @param the downstream value type * @param source the source reactive type ({@code Flowable} or {@code Observable}) * possibly implementing {@link Supplier}. * @param mapper the function that turns the scalar upstream value into a diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/SingleFlatMapObservable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/SingleFlatMapObservable.java index c3dd9b59c1f..5db75158907 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/SingleFlatMapObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/mixed/SingleFlatMapObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -106,7 +106,9 @@ public void onSuccess(T t) { return; } - o.subscribe(this); + if (!isDisposed()) { + o.subscribe(this); + } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/AbstractObservableWithUpstream.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/AbstractObservableWithUpstream.java index 2225cb2d2a8..dcad29a5d8e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/AbstractObservableWithUpstream.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/AbstractObservableWithUpstream.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableIterable.java index dce3e2bc212..561571febff 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,8 +20,8 @@ import io.reactivex.rxjava3.core.ObservableSource; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; public final class BlockingObservableIterable implements Iterable { final ObservableSource source; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableLatest.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableLatest.java index e431db42a7e..4aca95b210b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableLatest.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableLatest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableMostRecent.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableMostRecent.java index 1332351cacb..0b2ea5bd34d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableMostRecent.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableMostRecent.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,7 +23,7 @@ * Returns an Iterable that always returns the item most recently emitted by an Observable, or a * seed value if no item has yet been emitted. *

- * + * * * @param the value type */ diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableNext.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableNext.java index 53aed40999f..2bbfe2b036d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableNext.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableNext.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ /** * Returns an Iterable that blocks until the Observable emits another item, then returns that item. *

- * + * * * @param the value type */ diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAll.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAll.java index 3f62b4732ce..0f365414c67 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAll.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAll.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.core.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAllSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAllSingle.java index 8c167d4c47a..89e4e38a163 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAllSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAllSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.core.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAmb.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAmb.java index 8bc43aa41cf..f8841956c68 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAmb.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAmb.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -115,9 +115,8 @@ public boolean win(int index) { } return true; } - return false; } - return w == index; + return false; } @Override diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAny.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAny.java index bda497f7ed8..fad20eb6e29 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAny.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAny.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.core.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAnySingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAnySingle.java index 6e263a0d480..ff7875fb54a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAnySingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAnySingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.core.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAutoConnect.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAutoConnect.java index 393a9a3f946..d00a2fc2912 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAutoConnect.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAutoConnect.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBlockingSubscribe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBlockingSubscribe.java index 2c88f007e90..e173785760a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBlockingSubscribe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBlockingSubscribe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -39,6 +39,7 @@ private ObservableBlockingSubscribe() { * The call to dispose() is composed through. * @param observer the subscriber to forward events and calls to in the current thread * @param the value type + * @throws NullPointerException if {@code observer} is {@code null} */ public static void subscribe(ObservableSource o, Observer observer) { final BlockingQueue queue = new LinkedBlockingQueue<>(); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBuffer.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBuffer.java index 2688212575d..6f94a97cc6d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBuffer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBuffer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferBoundary.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferBoundary.java index 4b0027f4fe2..4b0fafb1882 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferBoundary.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferBoundary.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,8 +22,8 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.AtomicThrowable; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class ObservableBufferBoundary, Open, Close> diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferExactBoundary.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferExactBoundary.java index 849222505ee..bb650589085 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferExactBoundary.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferExactBoundary.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -43,7 +43,7 @@ protected void subscribeActual(Observer t) { } static final class BufferExactBoundaryObserver, B> - extends QueueDrainObserver implements Observer, Disposable { + extends QueueDrainObserver implements Disposable { final Supplier bufferSupplier; final ObservableSource boundary; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferTimed.java index 8a7becc241e..7628a8f685d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -121,11 +121,9 @@ public void onSubscribe(Disposable d) { downstream.onSubscribe(this); - if (!cancelled) { + if (!DisposableHelper.isDisposed(timer.get())) { Disposable task = scheduler.schedulePeriodicallyDirect(this, timespan, timespan, unit); - if (!timer.compareAndSet(null, task)) { - task.dispose(); - } + DisposableHelper.set(timer, task); } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCache.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCache.java index c3e7447e6e3..99e11259a6f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCache.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCache.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,23 +24,7 @@ * * @param the source element type */ -public final class ObservableCache extends AbstractObservableWithUpstream -implements Observer { - - /** - * The subscription to the source should happen at most once. - */ - final AtomicBoolean once; - - /** - * The number of items per cached nodes. - */ - final int capacityHint; - - /** - * The current known array of observer state to notify. - */ - final AtomicReference[]> observers; +public final class ObservableCache extends AbstractObservableWithUpstream { /** * A shared instance of an empty array of observers to avoid creating @@ -56,61 +40,49 @@ public final class ObservableCache extends AbstractObservableWithUpstream head; - - /** - * The current tail of the linked structure holding the items. - */ - Node tail; - - /** - * How many items have been put into the tail node so far. + * The subscription to the source should happen at most once. */ - int tailOffset; + final AtomicBoolean once; /** - * If {@link #observers} is {@link #TERMINATED}, this holds the terminal error if not null. + * Responsible caching events from the source and multicasting them to each downstream. */ - Throwable error; + final Multicaster multicaster; /** - * True if the source has terminated. + * The first node in a singly linked list. Each node has the capacity to hold a specific number of events, and each + * points exclusively to the next node (if present). When a new downstream arrives, the subscription is + * initialized with a reference to the "head" node, and any events present in the linked list are replayed. As + * events are replayed to the new downstream, its 'node' reference advances through the linked list, discarding each + * node reference once all events in that node have been replayed. Consequently, once {@code this} instance goes out + * of scope, the prefix of nodes up to the first node that is still being replayed becomes unreachable and eligible + * for collection. */ - volatile boolean done; + final Node head; /** * Constructs an empty, non-connected cache. * @param source the source to subscribe to for the first incoming observer * @param capacityHint the number of items expected (reduce allocation frequency) */ - @SuppressWarnings("unchecked") public ObservableCache(Observable source, int capacityHint) { super(source); - this.capacityHint = capacityHint; this.once = new AtomicBoolean(); Node n = new Node<>(capacityHint); this.head = n; - this.tail = n; - this.observers = new AtomicReference<>(EMPTY); + this.multicaster = new Multicaster<>(capacityHint, n); } @Override protected void subscribeActual(Observer t) { - CacheDisposable consumer = new CacheDisposable<>(t, this); + CacheDisposable consumer = new CacheDisposable<>(t, multicaster, head); t.onSubscribe(consumer); - add(consumer); + multicaster.add(consumer); if (!once.get() && once.compareAndSet(false, true)) { - source.subscribe(this); + source.subscribe(multicaster); } else { - replay(consumer); + multicaster.replay(consumer); } } @@ -127,7 +99,7 @@ protected void subscribeActual(Observer t) { * @return true if the cache has observers */ /* public */ boolean hasObservers() { - return observers.get().length != 0; + return multicaster.get().length != 0; } /** @@ -135,194 +107,241 @@ protected void subscribeActual(Observer t) { * @return the number of currently cached event count */ /* public */ long cachedEventCount() { - return size; + return multicaster.size; } - /** - * Atomically adds the consumer to the {@link #observers} copy-on-write array - * if the source has not yet terminated. - * @param consumer the consumer to add - */ - void add(CacheDisposable consumer) { - for (;;) { - CacheDisposable[] current = observers.get(); - if (current == TERMINATED) { - return; - } - int n = current.length; + static final class Multicaster extends AtomicReference[]> implements Observer { - @SuppressWarnings("unchecked") - CacheDisposable[] next = new CacheDisposable[n + 1]; - System.arraycopy(current, 0, next, 0, n); - next[n] = consumer; + /** */ + private static final long serialVersionUID = 8514643269016498691L; - if (observers.compareAndSet(current, next)) { - return; - } - } - } + /** + * The number of items per cached nodes. + */ + final int capacityHint; - /** - * Atomically removes the consumer from the {@link #observers} copy-on-write array. - * @param consumer the consumer to remove - */ - @SuppressWarnings("unchecked") - void remove(CacheDisposable consumer) { - for (;;) { - CacheDisposable[] current = observers.get(); - int n = current.length; - if (n == 0) { - return; - } + /** + * The total number of elements in the list available for reads. + */ + volatile long size; - int j = -1; - for (int i = 0; i < n; i++) { - if (current[i] == consumer) { - j = i; - break; - } - } + /** + * The current tail of the linked structure holding the items. + */ + Node tail; - if (j < 0) { - return; - } - CacheDisposable[] next; + /** + * How many items have been put into the tail node so far. + */ + int tailOffset; - if (n == 1) { - next = EMPTY; - } else { - next = new CacheDisposable[n - 1]; - System.arraycopy(current, 0, next, 0, j); - System.arraycopy(current, j + 1, next, j, n - j - 1); - } + /** + * If the observers are {@link #TERMINATED}, this holds the terminal error if not null. + */ + Throwable error; - if (observers.compareAndSet(current, next)) { - return; - } - } - } + /** + * True if the source has terminated. + */ + volatile boolean done; - /** - * Replays the contents of this cache to the given consumer based on its - * current state and number of items requested by it. - * @param consumer the consumer to continue replaying items to - */ - void replay(CacheDisposable consumer) { - // make sure there is only one replay going on at a time - if (consumer.getAndIncrement() != 0) { - return; + @SuppressWarnings("unchecked") + Multicaster(int capacityHint, final Node head) { + super(EMPTY); + this.tail = head; + this.capacityHint = capacityHint; } - // see if there were more replay request in the meantime - int missed = 1; - // read out state into locals upfront to avoid being re-read due to volatile reads - long index = consumer.index; - int offset = consumer.offset; - Node node = consumer.node; - Observer downstream = consumer.downstream; - int capacity = capacityHint; - - for (;;) { - // if the consumer got disposed, clear the node and quit - if (consumer.disposed) { - consumer.node = null; - return; + /** + * Atomically adds the consumer to the observers copy-on-write array + * if the source has not yet terminated. + * @param consumer the consumer to add + */ + void add(CacheDisposable consumer) { + for (;;) { + CacheDisposable[] current = get(); + if (current == TERMINATED) { + return; + } + int n = current.length; + + @SuppressWarnings("unchecked") + CacheDisposable[] next = new CacheDisposable[n + 1]; + System.arraycopy(current, 0, next, 0, n); + next[n] = consumer; + + if (compareAndSet(current, next)) { + return; + } } + } - // first see if the source has terminated, read order matters! - boolean sourceDone = done; - // and if the number of items is the same as this consumer has received - boolean empty = size == index; - - // if the source is done and we have all items so far, terminate the consumer - if (sourceDone && empty) { - // release the node object to avoid leaks through retained consumers - consumer.node = null; - // if error is not null then the source failed - Throwable ex = error; - if (ex != null) { - downstream.onError(ex); + /** + * Atomically removes the consumer from the observers copy-on-write array. + * @param consumer the consumer to remove + */ + @SuppressWarnings("unchecked") + void remove(CacheDisposable consumer) { + for (;;) { + CacheDisposable[] current = get(); + int n = current.length; + if (n == 0) { + return; + } + + int j = -1; + for (int i = 0; i < n; i++) { + if (current[i] == consumer) { + j = i; + break; + } + } + + if (j < 0) { + return; + } + CacheDisposable[] next; + + if (n == 1) { + next = EMPTY; } else { - downstream.onComplete(); + next = new CacheDisposable[n - 1]; + System.arraycopy(current, 0, next, 0, j); + System.arraycopy(current, j + 1, next, j, n - j - 1); } + + if (compareAndSet(current, next)) { + return; + } + } + } + + /** + * Replays the contents of this cache to the given consumer based on its + * current state and number of items requested by it. + * @param consumer the consumer to continue replaying items to + */ + void replay(CacheDisposable consumer) { + // make sure there is only one replay going on at a time + if (consumer.getAndIncrement() != 0) { return; } - // there are still items not sent to the consumer - if (!empty) { - // if the offset in the current node has reached the node capacity - if (offset == capacity) { - // switch to the subsequent node - node = node.next; - // reset the in-node offset - offset = 0; + // see if there were more replay request in the meantime + int missed = 1; + // read out state into locals upfront to avoid being re-read due to volatile reads + long index = consumer.index; + int offset = consumer.offset; + Node node = consumer.node; + Observer downstream = consumer.downstream; + int capacity = capacityHint; + + for (;;) { + // if the consumer got disposed, clear the node and quit + if (consumer.disposed) { + consumer.node = null; + return; } - // emit the cached item - downstream.onNext(node.values[offset]); - - // move the node offset forward - offset++; - // move the total consumed item count forward - index++; + // first see if the source has terminated, read order matters! + boolean sourceDone = done; + // and if the number of items is the same as this consumer has received + boolean empty = size == index; + + // if the source is done and we have all items so far, terminate the consumer + if (sourceDone && empty) { + // release the node object to avoid leaks through retained consumers + consumer.node = null; + // if error is not null then the source failed + Throwable ex = error; + if (ex != null) { + downstream.onError(ex); + } else { + downstream.onComplete(); + } + return; + } - // retry for the next item/terminal event if any - continue; - } + // there are still items not sent to the consumer + if (!empty) { + // if the offset in the current node has reached the node capacity + if (offset == capacity) { + // switch to the subsequent node + node = node.next; + // reset the in-node offset + offset = 0; + } + + // emit the cached item + downstream.onNext(node.values[offset]); + + // move the node offset forward + offset++; + // move the total consumed item count forward + index++; + + // retry for the next item/terminal event if any + continue; + } - // commit the changed references back - consumer.index = index; - consumer.offset = offset; - consumer.node = node; - // release the changes and see if there were more replay request in the meantime - missed = consumer.addAndGet(-missed); - if (missed == 0) { - break; + // commit the changed references back + consumer.index = index; + consumer.offset = offset; + consumer.node = node; + // release the changes and see if there were more replay request in the meantime + missed = consumer.addAndGet(-missed); + if (missed == 0) { + break; + } } } - } - @Override - public void onSubscribe(Disposable d) { - // we can't do much with the upstream disposable - } - - @Override - public void onNext(T t) { - int tailOffset = this.tailOffset; - // if the current tail node is full, create a fresh node - if (tailOffset == capacityHint) { - Node n = new Node<>(tailOffset); - n.values[0] = t; - this.tailOffset = 1; - tail.next = n; - tail = n; - } else { - tail.values[tailOffset] = t; - this.tailOffset = tailOffset + 1; + @Override + public void onSubscribe(Disposable d) { + // we can't do much with the upstream disposable } - size++; - for (CacheDisposable consumer : observers.get()) { - replay(consumer); + + @Override + public void onNext(T t) { + int tailOffset = this.tailOffset; + // if the current tail node is full, create a fresh node + if (tailOffset == capacityHint) { + Node n = new Node<>(tailOffset); + n.values[0] = t; + this.tailOffset = 1; + tail.next = n; + tail = n; + } else { + tail.values[tailOffset] = t; + this.tailOffset = tailOffset + 1; + } + size++; + for (CacheDisposable consumer : get()) { + replay(consumer); + } } - } - @SuppressWarnings("unchecked") - @Override - public void onError(Throwable t) { - error = t; - done = true; - for (CacheDisposable consumer : observers.getAndSet(TERMINATED)) { - replay(consumer); + @SuppressWarnings("unchecked") + @Override + public void onError(Throwable t) { + error = t; + done = true; + // No additional events will arrive, so now we can clear the 'tail' reference + tail = null; + for (CacheDisposable consumer : getAndSet(TERMINATED)) { + replay(consumer); + } } - } - @SuppressWarnings("unchecked") - @Override - public void onComplete() { - done = true; - for (CacheDisposable consumer : observers.getAndSet(TERMINATED)) { - replay(consumer); + @SuppressWarnings("unchecked") + @Override + public void onComplete() { + done = true; + // No additional events will arrive, so now we can clear the 'tail' reference + tail = null; + for (CacheDisposable consumer : getAndSet(TERMINATED)) { + replay(consumer); + } } } @@ -338,7 +357,7 @@ static final class CacheDisposable extends AtomicInteger final Observer downstream; - final ObservableCache parent; + final Multicaster parent; Node node; @@ -353,11 +372,12 @@ static final class CacheDisposable extends AtomicInteger * the parent cache object. * @param downstream the actual consumer * @param parent the parent that holds onto the cached items + * @param head the first node in the linked list */ - CacheDisposable(Observer downstream, ObservableCache parent) { + CacheDisposable(Observer downstream, Multicaster parent, Node head) { this.downstream = downstream; this.parent = parent; - this.node = parent.head; + this.node = head; } @Override diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCollect.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCollect.java index 6bddb34aac7..6b700addd73 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCollect.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCollect.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.core.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCollectSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCollectSingle.java index 82f8923de3f..88137432ac3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCollectSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCollectSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.core.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCombineLatest.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCombineLatest.java index 34dce804315..fded0d0ef59 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCombineLatest.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCombineLatest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,8 +21,8 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.AtomicThrowable; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; public final class ObservableCombineLatest extends Observable { final ObservableSource[] sources; @@ -49,13 +49,19 @@ public void subscribeActual(Observer observer) { int count = 0; if (sources == null) { sources = new ObservableSource[8]; - for (ObservableSource p : sourcesIterable) { - if (count == sources.length) { - ObservableSource[] b = new ObservableSource[count + (count >> 2)]; - System.arraycopy(sources, 0, b, 0, count); - sources = b; + try { + for (ObservableSource p : sourcesIterable) { + if (count == sources.length) { + ObservableSource[] b = new ObservableSource[count + (count >> 2)]; + System.arraycopy(sources, 0, b, 0, count); + sources = b; + } + sources[count++] = Objects.requireNonNull(p, "The Iterator returned a null ObservableSource"); } - sources[count++] = p; + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + EmptyDisposable.error(ex, observer); + return; } } else { count = sources.length; @@ -122,9 +128,7 @@ public void dispose() { if (!cancelled) { cancelled = true; cancelSources(); - if (getAndIncrement() == 0) { - clear(queue); - } + drain(); } } @@ -161,6 +165,7 @@ void drain() { for (;;) { if (cancelled) { clear(q); + errors.tryTerminateAndReport(); return; } @@ -240,7 +245,6 @@ void innerError(int index, Throwable ex) { if (latest == null) { return; } - cancelOthers = latest[index] == null; if (cancelOthers || ++complete == latest.length) { done = true; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMap.java index 9b03b9fc35c..b8f34df3d7f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import java.util.Objects; @@ -20,10 +21,11 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.*; import io.reactivex.rxjava3.observers.SerializedObserver; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class ObservableConcatMap extends AbstractObservableWithUpstream { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapEager.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapEager.java index 792940b5e06..5a4b1c3a472 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapEager.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapEager.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,10 +22,11 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.observers.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; public final class ObservableConcatMapEager extends AbstractObservableWithUpstream { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapScheduler.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapScheduler.java index b4cd8352b5b..1ea59c83c38 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapScheduler.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapScheduler.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import java.util.Objects; @@ -20,10 +21,11 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.*; import io.reactivex.rxjava3.observers.SerializedObserver; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class ObservableConcatMapScheduler extends AbstractObservableWithUpstream { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithCompletable.java index 4ffc8f5490e..8d97074a8c4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithMaybe.java index 19af4e56412..e198a0412a8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithSingle.java index b2e18601101..3d69ae83ac1 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCount.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCount.java index f7ab3b012f5..366c4bb3dbe 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCount.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCount.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCountSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCountSingle.java index 5796519f740..be73420542e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCountSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCountSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCreate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCreate.java index 66445bc8d19..1e2e910f0f5 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCreate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCreate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import java.util.concurrent.atomic.*; @@ -19,9 +20,9 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Cancellable; import io.reactivex.rxjava3.internal.disposables.*; -import io.reactivex.rxjava3.internal.fuseable.SimpleQueue; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class ObservableCreate extends Observable { @@ -159,7 +160,7 @@ static final class SerializedEmitter @Override public void onNext(T t) { - if (emitter.isDisposed() || done) { + if (done || emitter.isDisposed()) { return; } if (t == null) { @@ -192,7 +193,7 @@ public void onError(Throwable t) { @Override public boolean tryOnError(Throwable t) { - if (emitter.isDisposed() || done) { + if (done || emitter.isDisposed()) { return false; } if (t == null) { @@ -208,7 +209,7 @@ public boolean tryOnError(Throwable t) { @Override public void onComplete() { - if (emitter.isDisposed() || done) { + if (done || emitter.isDisposed()) { return; } done = true; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDebounce.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDebounce.java index 16f882d6c53..862227e305b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDebounce.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDebounce.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDebounceTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDebounceTimed.java index b0b19ef0dc1..f2db191229f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDebounceTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDebounceTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,6 +19,8 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Scheduler.Worker; import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.Consumer; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; import io.reactivex.rxjava3.observers.SerializedObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; @@ -27,19 +29,20 @@ public final class ObservableDebounceTimed extends AbstractObservableWithUpst final long timeout; final TimeUnit unit; final Scheduler scheduler; + final Consumer onDropped; - public ObservableDebounceTimed(ObservableSource source, long timeout, TimeUnit unit, Scheduler scheduler) { + public ObservableDebounceTimed(ObservableSource source, long timeout, TimeUnit unit, Scheduler scheduler, Consumer onDropped) { super(source); this.timeout = timeout; this.unit = unit; this.scheduler = scheduler; + this.onDropped = onDropped; } @Override public void subscribeActual(Observer t) { source.subscribe(new DebounceTimedObserver<>( - new SerializedObserver<>(t), - timeout, unit, scheduler.createWorker())); + new SerializedObserver<>(t), timeout, unit, scheduler.createWorker(), onDropped)); } static final class DebounceTimedObserver @@ -48,20 +51,22 @@ static final class DebounceTimedObserver final long timeout; final TimeUnit unit; final Scheduler.Worker worker; + final Consumer onDropped; Disposable upstream; - Disposable timer; + DebounceEmitter timer; volatile long index; boolean done; - DebounceTimedObserver(Observer actual, long timeout, TimeUnit unit, Worker worker) { + DebounceTimedObserver(Observer actual, long timeout, TimeUnit unit, Worker worker, Consumer onDropped) { this.downstream = actual; this.timeout = timeout; this.unit = unit; this.worker = worker; + this.onDropped = onDropped; } @Override @@ -80,15 +85,25 @@ public void onNext(T t) { long idx = index + 1; index = idx; - Disposable d = timer; - if (d != null) { - d.dispose(); + DebounceEmitter currentEmitter = timer; + if (currentEmitter != null) { + currentEmitter.dispose(); } - DebounceEmitter de = new DebounceEmitter<>(t, idx, this); - timer = de; - d = worker.schedule(de, timeout, unit); - de.setResource(d); + if (onDropped != null && currentEmitter != null) { + try { + onDropped.accept(timer.value); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.dispose(); + downstream.onError(ex); + done = true; + } + } + + DebounceEmitter newEmitter = new DebounceEmitter<>(t, idx, this); + timer = newEmitter; + newEmitter.setResource(worker.schedule(newEmitter, timeout, unit)); } @Override @@ -113,15 +128,13 @@ public void onComplete() { } done = true; - Disposable d = timer; + DebounceEmitter d = timer; if (d != null) { d.dispose(); } - @SuppressWarnings("unchecked") - DebounceEmitter de = (DebounceEmitter)d; - if (de != null) { - de.run(); + if (d != null) { + d.run(); } downstream.onComplete(); worker.dispose(); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDefer.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDefer.java index 15b3394af70..0b3388c84c9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDefer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDefer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelay.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelay.java index 93cbb003893..7c01c23f90a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelay.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelay.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -111,7 +111,9 @@ final class OnNext implements Runnable { @Override public void run() { - downstream.onNext(t); + if (!w.isDisposed()) { + downstream.onNext(t); + } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelaySubscriptionOther.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelaySubscriptionOther.java index c594c68b007..978e4d2f32c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelaySubscriptionOther.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelaySubscriptionOther.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDematerialize.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDematerialize.java index 37f5fdadd81..20164519862 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDematerialize.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDematerialize.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDetach.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDetach.java index 763fcdde972..b9c6f2bade8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDetach.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDetach.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinct.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinct.java index cd766ef559e..ff377833a50 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinct.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinct.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinctUntilChanged.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinctUntilChanged.java index f18e47030d8..7604db7c8f8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinctUntilChanged.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinctUntilChanged.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoAfterNext.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoAfterNext.java index 91051e75626..6382e6b8221 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoAfterNext.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoAfterNext.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoFinally.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoFinally.java index 8c7ee32d09d..e6d9031f72e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoFinally.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoFinally.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,8 +19,8 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Action; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.QueueDisposable; import io.reactivex.rxjava3.internal.observers.BasicIntQueueDisposable; +import io.reactivex.rxjava3.operators.QueueDisposable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnEach.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnEach.java index ff884192fae..f4869d19a8a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnEach.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnEach.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnLifecycle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnLifecycle.java index 835cd886b2f..f1852312466 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnLifecycle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnLifecycle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.core.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAt.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAt.java index b8d042a5321..8d8a535bcf0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAt.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAt.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAtMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAtMaybe.java index 53b13120927..14bb368a23a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAtMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAtMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAtSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAtSingle.java index bb006ca2dd3..c779f9eec2a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAtSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAtSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableEmpty.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableEmpty.java index d4869b70eab..7ff9e8b955f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableEmpty.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableEmpty.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,11 +10,12 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.internal.disposables.EmptyDisposable; -import io.reactivex.rxjava3.internal.fuseable.ScalarSupplier; +import io.reactivex.rxjava3.operators.ScalarSupplier; public final class ObservableEmpty extends Observable implements ScalarSupplier { public static final Observable INSTANCE = new ObservableEmpty(); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableError.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableError.java index 7481373e7a6..f25af956e09 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableError.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableError.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFilter.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFilter.java index 51fec2cc680..ed7068f6a08 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFilter.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFilter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMap.java index a169627ed30..d19b5059992 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,9 +22,8 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.*; import io.reactivex.rxjava3.internal.util.AtomicThrowable; +import io.reactivex.rxjava3.operators.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class ObservableFlatMap extends AbstractObservableWithUpstream { @@ -69,7 +68,7 @@ static final class MergeObserver extends AtomicInteger implements Disposab final AtomicThrowable errors = new AtomicThrowable(); - volatile boolean cancelled; + volatile boolean disposed; final AtomicReference[]> observers; @@ -80,7 +79,6 @@ static final class MergeObserver extends AtomicInteger implements Disposab Disposable upstream; long uniqueId; - long lastId; int lastIndex; Queue> sources; @@ -188,9 +186,6 @@ void removeInner(InnerObserver inner) { for (;;) { InnerObserver[] a = observers.get(); int n = a.length; - if (n == 0) { - return; - } int j = -1; for (int i = 0; i < n; i++) { if (a[i] == inner) { @@ -246,10 +241,7 @@ boolean tryEmitScalar(Supplier value) { queue = q; } - if (!q.offer(u)) { - onError(new IllegalStateException("Scalar queue full?!")); - return true; - } + q.offer(u); if (getAndIncrement() != 0) { return false; } @@ -301,17 +293,15 @@ public void onComplete() { @Override public void dispose() { - if (!cancelled) { - cancelled = true; - if (disposeAll()) { - errors.tryTerminateAndReport(); - } + disposed = true; + if (disposeAll()) { + errors.tryTerminateAndReport(); } } @Override public boolean isDisposed() { - return cancelled; + return disposed; } void drain() { @@ -327,6 +317,7 @@ void drainLoop() { if (checkTerminate()) { return; } + int innerCompleted = 0; SimplePlainQueue svq = queue; if (svq != null) { @@ -342,9 +333,18 @@ void drainLoop() { } child.onNext(o); + innerCompleted++; } } + if (innerCompleted != 0) { + if (maxConcurrency != Integer.MAX_VALUE) { + subscribeMore(innerCompleted); + innerCompleted = 0; + } + continue; + } + boolean d = done; svq = queue; InnerObserver[] inner = observers.get(); @@ -362,31 +362,9 @@ void drainLoop() { return; } - int innerCompleted = 0; if (n != 0) { - long startId = lastId; - int index = lastIndex; - - if (n <= index || inner[index].id != startId) { - if (n <= index) { - index = 0; - } - int j = index; - for (int i = 0; i < n; i++) { - if (inner[j].id == startId) { - break; - } - j++; - if (j == n) { - j = 0; - } - } - index = j; - lastIndex = j; - lastId = inner[j].id; - } + int j = Math.min(n - 1, lastIndex); - int j = index; sourceLoop: for (int i = 0; i < n; i++) { if (checkTerminate()) { @@ -432,9 +410,6 @@ void drainLoop() { SimpleQueue innerQueue = is.queue; if (innerDone && (innerQueue == null || innerQueue.isEmpty())) { removeInner(is); - if (checkTerminate()) { - return; - } innerCompleted++; } @@ -444,25 +419,16 @@ void drainLoop() { } } lastIndex = j; - lastId = inner[j].id; } if (innerCompleted != 0) { if (maxConcurrency != Integer.MAX_VALUE) { - while (innerCompleted-- != 0) { - ObservableSource p; - synchronized (this) { - p = sources.poll(); - if (p == null) { - wip--; - continue; - } - } - subscribeInner(p); - } + subscribeMore(innerCompleted); + innerCompleted = 0; } continue; } + missed = addAndGet(-missed); if (missed == 0) { break; @@ -470,8 +436,22 @@ void drainLoop() { } } + void subscribeMore(int innerCompleted) { + while (innerCompleted-- != 0) { + ObservableSource p; + synchronized (this) { + p = sources.poll(); + if (p == null) { + wip--; + continue; + } + } + subscribeInner(p); + } + } + boolean checkTerminate() { - if (cancelled) { + if (disposed) { return true; } Throwable e = errors.get(); @@ -485,15 +465,12 @@ boolean checkTerminate() { boolean disposeAll() { upstream.dispose(); - InnerObserver[] a = observers.get(); + InnerObserver[] a = observers.getAndSet(CANCELLED); if (a != CANCELLED) { - a = observers.getAndSet(CANCELLED); - if (a != CANCELLED) { - for (InnerObserver inner : a) { - inner.dispose(); - } - return true; + for (InnerObserver inner : a) { + inner.dispose(); } + return true; } return false; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapCompletable.java index 729e8cf6c50..ae7c6f98ac0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -116,9 +116,7 @@ public void onError(Throwable e) { disposed = true; upstream.dispose(); set.dispose(); - if (getAndSet(0) > 0) { - errors.tryTerminateConsumer(downstream); - } + errors.tryTerminateConsumer(downstream); } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapCompletableCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapCompletableCompletable.java index 2d488ac2c5d..62ea03a54d3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapCompletableCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapCompletableCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -122,9 +122,7 @@ public void onError(Throwable e) { disposed = true; upstream.dispose(); set.dispose(); - if (getAndSet(0) > 0) { - errors.tryTerminateConsumer(downstream); - } + errors.tryTerminateConsumer(downstream); } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe.java index 7ac5ca6f3c9..b8d223d4ac3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,8 +21,8 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.AtomicThrowable; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; /** * Maps upstream values into MaybeSources and merges their signals into one sequence. @@ -172,16 +172,15 @@ void innerSuccess(InnerObserver inner, R value) { } SpscLinkedArrayQueue getOrCreateQueue() { - for (;;) { - SpscLinkedArrayQueue current = queue.get(); - if (current != null) { - return current; - } - current = new SpscLinkedArrayQueue<>(Observable.bufferSize()); - if (queue.compareAndSet(null, current)) { - return current; - } + SpscLinkedArrayQueue current = queue.get(); + if (current != null) { + return current; + } + current = new SpscLinkedArrayQueue<>(Observable.bufferSize()); + if (queue.compareAndSet(null, current)) { + return current; } + return queue.get(); } void innerError(InnerObserver inner, Throwable e) { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle.java index 8ed45d5f399..985e4fa2d91 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,8 +21,8 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.AtomicThrowable; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; /** * Maps upstream values into SingleSources and merges their signals into one sequence. @@ -172,16 +172,15 @@ void innerSuccess(InnerObserver inner, R value) { } SpscLinkedArrayQueue getOrCreateQueue() { - for (;;) { - SpscLinkedArrayQueue current = queue.get(); - if (current != null) { - return current; - } - current = new SpscLinkedArrayQueue<>(Observable.bufferSize()); - if (queue.compareAndSet(null, current)) { - return current; - } + SpscLinkedArrayQueue current = queue.get(); + if (current != null) { + return current; + } + current = new SpscLinkedArrayQueue<>(Observable.bufferSize()); + if (queue.compareAndSet(null, current)) { + return current; } + return queue.get(); } void innerError(InnerObserver inner, Throwable e) { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlattenIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlattenIterable.java index 732eb50dd3b..47dbde9a1ed 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlattenIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlattenIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromAction.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromAction.java new file mode 100644 index 00000000000..cd0970f0d06 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromAction.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.observable; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.fuseable.CancellableQueueFuseable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + +/** + * Executes an {@link Action} and signals its exception or completes normally. + * + * @param the value type + * @since 3.0.0 + */ +public final class ObservableFromAction extends Observable implements Supplier { + + final Action action; + + public ObservableFromAction(Action action) { + this.action = action; + } + + @Override + protected void subscribeActual(Observer observer) { + CancellableQueueFuseable qs = new CancellableQueueFuseable<>(); + observer.onSubscribe(qs); + + if (!qs.isDisposed()) { + + try { + action.run(); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + if (!qs.isDisposed()) { + observer.onError(ex); + } else { + RxJavaPlugins.onError(ex); + } + return; + } + + if (!qs.isDisposed()) { + observer.onComplete(); + } + } + } + + @Override + public T get() throws Throwable { + action.run(); + return null; // considered as onComplete() + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromArray.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromArray.java index 97ebfe0d4ff..f84c1183469 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromArray.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromArray.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCallable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCallable.java index 0285b83ff24..ab4b7aa7b89 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCallable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCallable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCompletable.java new file mode 100644 index 00000000000..83bf51f7e03 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCompletable.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.observable; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.internal.disposables.DisposableHelper; +import io.reactivex.rxjava3.internal.fuseable.*; + +/** + * Wrap a Completable into an Observable. + * + * @param the value type + * @since 3.0.0 + */ +public final class ObservableFromCompletable extends Observable implements HasUpstreamCompletableSource { + + final CompletableSource source; + + public ObservableFromCompletable(CompletableSource source) { + this.source = source; + } + + @Override + public CompletableSource source() { + return source; + } + + @Override + protected void subscribeActual(Observer observer) { + source.subscribe(new FromCompletableObserver(observer)); + } + + public static final class FromCompletableObserver + extends AbstractEmptyQueueFuseable + implements CompletableObserver { + + final Observer downstream; + + Disposable upstream; + + public FromCompletableObserver(Observer downstream) { + this.downstream = downstream; + } + + @Override + public void dispose() { + upstream.dispose(); + upstream = DisposableHelper.DISPOSED; + } + + @Override + public boolean isDisposed() { + return upstream.isDisposed(); + } + + @Override + public void onSubscribe(Disposable d) { + if (DisposableHelper.validate(this.upstream, d)) { + this.upstream = d; + + downstream.onSubscribe(this); + } + } + + @Override + public void onComplete() { + upstream = DisposableHelper.DISPOSED; + downstream.onComplete(); + } + + @Override + public void onError(Throwable e) { + upstream = DisposableHelper.DISPOSED; + downstream.onError(e); + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromFuture.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromFuture.java index 5459429f4de..d6f21ad133e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromFuture.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromFuture.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromIterable.java index 187d0cecc33..d5f402d1935 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher.java index 14efd74eba3..ade1eeb8707 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import org.reactivestreams.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromRunnable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromRunnable.java new file mode 100644 index 00000000000..eeda8e48328 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromRunnable.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.observable; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.Supplier; +import io.reactivex.rxjava3.internal.fuseable.CancellableQueueFuseable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + +/** + * Executes an {@link Runnable} and signals its exception or completes normally. + * + * @param the value type + * @since 3.0.0 + */ +public final class ObservableFromRunnable extends Observable implements Supplier { + + final Runnable run; + + public ObservableFromRunnable(Runnable run) { + this.run = run; + } + + @Override + protected void subscribeActual(Observer observer) { + CancellableQueueFuseable qs = new CancellableQueueFuseable<>(); + observer.onSubscribe(qs); + + if (!qs.isDisposed()) { + + try { + run.run(); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + if (!qs.isDisposed()) { + observer.onError(ex); + } else { + RxJavaPlugins.onError(ex); + } + return; + } + + if (!qs.isDisposed()) { + observer.onComplete(); + } + } + } + + @Override + public T get() throws Throwable { + run.run(); + return null; // considered as onComplete() + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromSupplier.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromSupplier.java index e46cf8fe8fc..7d3cd41480f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromSupplier.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromSupplier.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromUnsafeSource.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromUnsafeSource.java index d34423bcd43..1f7c7bcccdc 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromUnsafeSource.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromUnsafeSource.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGenerate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGenerate.java index 2bd9a866a14..fee8dfe26ea 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGenerate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGenerate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupBy.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupBy.java index 8e259db47cc..e1af50378e8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupBy.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupBy.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,8 +23,8 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.observables.GroupedObservable; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; public final class ObservableGroupBy extends AbstractObservableWithUpstream> { final Function keySelector; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupJoin.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupJoin.java index 3605ee5203f..4df7fc7bd84 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupJoin.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupJoin.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.operators.observable; @@ -26,8 +23,8 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.ExceptionHelper; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.subjects.UnicastSubject; @@ -319,7 +316,7 @@ else if (mode == LEFT_CLOSE) { up.onComplete(); } } - else if (mode == RIGHT_CLOSE) { + else { LeftRightEndObserver end = (LeftRightEndObserver)val; rights.remove(end.index); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableHide.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableHide.java index 5b216cd44c9..8d6c7a7b60a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableHide.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableHide.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIgnoreElements.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIgnoreElements.java index ec4a07e92a9..6afab8124d6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIgnoreElements.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIgnoreElements.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIgnoreElementsCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIgnoreElementsCompletable.java index 14b3a776845..10e4880b55a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIgnoreElementsCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIgnoreElementsCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableInternalHelper.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableInternalHelper.java index 5f9dce646df..89822c3e9b4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableInternalHelper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableInternalHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import java.util.Objects; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableInterval.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableInterval.java index 93fee0973d3..c61645bdd97 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableInterval.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableInterval.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIntervalRange.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIntervalRange.java index 96d113663e1..68d303b6ab0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIntervalRange.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIntervalRange.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -90,8 +90,10 @@ public void run() { downstream.onNext(c); if (c == end) { + if (!isDisposed()) { + downstream.onComplete(); + } DisposableHelper.dispose(this); - downstream.onComplete(); return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableJoin.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableJoin.java index 70f62aec032..4a0f95695e3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableJoin.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableJoin.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.operators.observable; @@ -25,8 +22,8 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.operators.observable.ObservableGroupJoin.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.ExceptionHelper; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class ObservableJoin extends AbstractObservableWithUpstream { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableJust.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableJust.java index d3448d0b413..af01eb09bb4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableJust.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableJust.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,8 +14,8 @@ package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.internal.fuseable.ScalarSupplier; import io.reactivex.rxjava3.internal.operators.observable.ObservableScalarXMap.ScalarDisposable; +import io.reactivex.rxjava3.operators.ScalarSupplier; /** * Represents a constant scalar value. diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLastMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLastMaybe.java index 73e26a3972e..b20119d4306 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLastMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLastMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLastSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLastSingle.java index 7c5433e1057..049e9341c10 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLastSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLastSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLift.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLift.java index 4aa45683ffa..67dd7a06498 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLift.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLift.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMap.java index 4361016ec6e..8f4502ba192 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMapNotification.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMapNotification.java index 1622b504d43..51883e75193 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMapNotification.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMapNotification.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMaterialize.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMaterialize.java index e55430c3782..866ced7dd98 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMaterialize.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMaterialize.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithCompletable.java index 1f086f7175e..e1a79180d87 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithMaybe.java index f462075a506..4e940a74f5d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,9 +18,9 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.AtomicThrowable; +import io.reactivex.rxjava3.operators.SimplePlainQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; /** * Merges an Observable and a Maybe by emitting the items of the Observable and the success diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithSingle.java index 08940cf6452..014df98cc29 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,9 +18,9 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.AtomicThrowable; +import io.reactivex.rxjava3.operators.SimplePlainQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; /** * Merges an Observable and a Single by emitting the items of the Observable and the success diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableNever.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableNever.java index dd476d59932..1d237491ccd 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableNever.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableNever.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.core.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn.java index af5e78df3f3..05a0064f41a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableObserveOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,10 +18,11 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.observers.BasicIntQueueDisposable; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.schedulers.TrampolineScheduler; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class ObservableObserveOn extends AbstractObservableWithUpstream { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorComplete.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorComplete.java new file mode 100644 index 00000000000..70266c14d32 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorComplete.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.observable; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.functions.Predicate; +import io.reactivex.rxjava3.internal.disposables.DisposableHelper; + +/** + * Emits an onComplete if the source emits an onError and the predicate returns true for + * that Throwable. + * + * @param the value type + * @since 3.0.0 + */ +public final class ObservableOnErrorComplete extends AbstractObservableWithUpstream { + + final Predicate predicate; + + public ObservableOnErrorComplete(ObservableSource source, + Predicate predicate) { + super(source); + this.predicate = predicate; + } + + @Override + protected void subscribeActual(Observer observer) { + source.subscribe(new OnErrorCompleteObserver<>(observer, predicate)); + } + + public static final class OnErrorCompleteObserver + implements Observer, Disposable { + + final Observer downstream; + + final Predicate predicate; + + Disposable upstream; + + public OnErrorCompleteObserver(Observer actual, Predicate predicate) { + this.downstream = actual; + this.predicate = predicate; + } + + @Override + public void onSubscribe(Disposable d) { + if (DisposableHelper.validate(this.upstream, d)) { + this.upstream = d; + + downstream.onSubscribe(this); + } + } + + @Override + public void onNext(T value) { + downstream.onNext(value); + } + + @Override + public void onError(Throwable e) { + boolean b; + + try { + b = predicate.test(e); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + downstream.onError(new CompositeException(e, ex)); + return; + } + + if (b) { + downstream.onComplete(); + } else { + downstream.onError(e); + } + } + + @Override + public void onComplete() { + downstream.onComplete(); + } + + @Override + public void dispose() { + upstream.dispose(); + } + + @Override + public boolean isDisposed() { + return upstream.isDisposed(); + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorNext.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorNext.java index 3cf18490117..9bcc3b8dd69 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorNext.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorNext.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorReturn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorReturn.java index 54efdc62e5c..24c9af47005 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorReturn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorReturn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservablePublish.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservablePublish.java index 8589ee3c8a5..f2d4c8f0f4b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservablePublish.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservablePublish.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservablePublishSelector.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservablePublishSelector.java index 687bee95484..d025a5487de 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservablePublishSelector.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservablePublishSelector.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRange.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRange.java index 56e277dc32b..53855a46c23 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRange.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRange.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.annotations.Nullable; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRangeLong.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRangeLong.java index f92decb11e9..39a36e72f2c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRangeLong.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRangeLong.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.annotations.Nullable; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceMaybe.java index f5421a666eb..3f66614ef0a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceSeedSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceSeedSingle.java index 67347debb84..f2382f6f9d2 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceSeedSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceSeedSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceWithSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceWithSingle.java index 1de6cb1e6c5..22dbaa6a1d6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceWithSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceWithSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRefCount.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRefCount.java index a806a537c65..1a5d9f55ccf 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRefCount.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRefCount.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeat.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeat.java index 2816dac708c..b14549f65f7 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeat.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeat.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeatUntil.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeatUntil.java index 51c8b9dd656..d89fd17b830 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeatUntil.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeatUntil.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeatWhen.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeatWhen.java index d3fcdf59710..87d30330bae 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeatWhen.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeatWhen.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReplay.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReplay.java index 7dabfcc72d2..0e8c122d624 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReplay.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReplay.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -122,6 +122,7 @@ public static ConnectableObservable create(ObservableSource source, /** * Creates a OperatorReplay instance to replay values of the given source observable. + * @param the value type * @param source the source observable * @param bufferFactory the factory to instantiate the appropriate buffer when the observable becomes active * @return the connectable observable @@ -174,7 +175,7 @@ public void connect(Consumer connection) { // create a new subscriber-to-source ReplayBuffer buf = bufferFactory.call(); - ReplayObserver u = new ReplayObserver<>(buf); + ReplayObserver u = new ReplayObserver<>(buf, current); // try setting it as the current subscriber-to-source if (!current.compareAndSet(ps, u)) { // did not work, perhaps a new subscriber arrived @@ -240,8 +241,12 @@ static final class ReplayObserver */ final AtomicBoolean shouldConnect; - ReplayObserver(ReplayBuffer buffer) { + /** The current connection. */ + final AtomicReference> current; + + ReplayObserver(ReplayBuffer buffer, AtomicReference> current) { this.buffer = buffer; + this.current = current; this.observers = new AtomicReference<>(EMPTY); this.shouldConnect = new AtomicBoolean(); @@ -255,9 +260,7 @@ public boolean isDisposed() { @Override public void dispose() { observers.set(TERMINATED); - // unlike OperatorPublish, we can't null out the terminated so - // late observers can still get replay - // current.compareAndSet(ReplayObserver.this, null); + current.compareAndSet(ReplayObserver.this, null); // we don't care if it fails because it means the current has // been replaced in the meantime DisposableHelper.dispose(this); @@ -451,6 +454,7 @@ public void dispose() { } /** * Convenience method to auto-cast the index object. + * @param type index to be casted to * @return the index Object or null */ @SuppressWarnings("unchecked") @@ -846,7 +850,7 @@ void truncate() { int e = 0; for (;;) { - if (next != null && size > 1) { // never truncate the very last item just added + if (size > 1) { // never truncate the very last item just added if (size > limit) { e++; size--; @@ -881,7 +885,7 @@ void truncateFinal() { int e = 0; for (;;) { - if (next != null && size > 1) { + if (size > 1) { Timed v = (Timed)next.value; if (v.time() <= timeLimit) { e++; @@ -1004,7 +1008,7 @@ public void subscribe(Observer child) { // create a new subscriber to source ReplayBuffer buf = bufferFactory.call(); - ReplayObserver u = new ReplayObserver<>(buf); + ReplayObserver u = new ReplayObserver<>(buf, curr); // let's try setting it as the current subscriber-to-source if (!curr.compareAndSet(null, u)) { // didn't work, maybe someone else did it or the current subscriber @@ -1069,29 +1073,4 @@ protected void subscribeActual(Observer child) { co.connect(new DisposeConsumer<>(srw)); } } - - static final class Replay extends ConnectableObservable { - private final ConnectableObservable co; - private final Observable observable; - - Replay(ConnectableObservable co, Observable observable) { - this.co = co; - this.observable = observable; - } - - @Override - public void connect(Consumer connection) { - co.connect(connection); - } - - @Override - public void reset() { - co.reset(); - } - - @Override - protected void subscribeActual(Observer observer) { - observable.subscribe(observer); - } - } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryBiPredicate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryBiPredicate.java index 56de8606be9..1340a5ad9fa 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryBiPredicate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryBiPredicate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryPredicate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryPredicate.java index 9c4d5c748ab..5c40dc6d977 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryPredicate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryPredicate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryWhen.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryWhen.java index 2a3f0b6b074..bae50456e4d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryWhen.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryWhen.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSampleTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSampleTimed.java index 3f516e8cca1..f264b8e76d4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSampleTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSampleTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,6 +18,8 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.Consumer; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; import io.reactivex.rxjava3.observers.SerializedObserver; @@ -25,24 +27,30 @@ public final class ObservableSampleTimed extends AbstractObservableWithUpstre final long period; final TimeUnit unit; final Scheduler scheduler; - + final Consumer onDropped; final boolean emitLast; - public ObservableSampleTimed(ObservableSource source, long period, TimeUnit unit, Scheduler scheduler, boolean emitLast) { + public ObservableSampleTimed(ObservableSource source, + long period, + TimeUnit unit, + Scheduler scheduler, + boolean emitLast, + Consumer onDropped) { super(source); this.period = period; this.unit = unit; this.scheduler = scheduler; this.emitLast = emitLast; + this.onDropped = onDropped; } @Override public void subscribeActual(Observer t) { SerializedObserver serial = new SerializedObserver<>(t); if (emitLast) { - source.subscribe(new SampleTimedEmitLast<>(serial, period, unit, scheduler)); + source.subscribe(new SampleTimedEmitLast<>(serial, period, unit, scheduler, onDropped)); } else { - source.subscribe(new SampleTimedNoLast<>(serial, period, unit, scheduler)); + source.subscribe(new SampleTimedNoLast<>(serial, period, unit, scheduler, onDropped)); } } @@ -54,16 +62,18 @@ abstract static class SampleTimedObserver extends AtomicReference implemen final long period; final TimeUnit unit; final Scheduler scheduler; + final Consumer onDropped; final AtomicReference timer = new AtomicReference<>(); Disposable upstream; - SampleTimedObserver(Observer actual, long period, TimeUnit unit, Scheduler scheduler) { + SampleTimedObserver(Observer actual, long period, TimeUnit unit, Scheduler scheduler, Consumer onDropped) { this.downstream = actual; this.period = period; this.unit = unit; this.scheduler = scheduler; + this.onDropped = onDropped; } @Override @@ -79,7 +89,17 @@ public void onSubscribe(Disposable d) { @Override public void onNext(T t) { - lazySet(t); + T oldValue = getAndSet(t); + if (oldValue != null && onDropped != null) { + try { + onDropped.accept(oldValue); + } catch (Throwable throwable) { + Exceptions.throwIfFatal(throwable); + cancelTimer(); + upstream.dispose(); + downstream.onError(throwable); + } + } } @Override @@ -123,8 +143,8 @@ static final class SampleTimedNoLast extends SampleTimedObserver { private static final long serialVersionUID = -7139995637533111443L; - SampleTimedNoLast(Observer actual, long period, TimeUnit unit, Scheduler scheduler) { - super(actual, period, unit, scheduler); + SampleTimedNoLast(Observer actual, long period, TimeUnit unit, Scheduler scheduler, Consumer onDropped) { + super(actual, period, unit, scheduler, onDropped); } @Override @@ -144,8 +164,8 @@ static final class SampleTimedEmitLast extends SampleTimedObserver { final AtomicInteger wip; - SampleTimedEmitLast(Observer actual, long period, TimeUnit unit, Scheduler scheduler) { - super(actual, period, unit, scheduler); + SampleTimedEmitLast(Observer actual, long period, TimeUnit unit, Scheduler scheduler, Consumer onDropped) { + super(actual, period, unit, scheduler, onDropped); this.wip = new AtomicInteger(1); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSampleWithObservable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSampleWithObservable.java index cae3259d12e..53b9aec31f4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSampleWithObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSampleWithObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScalarXMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScalarXMap.java index c62c23c0c5b..7ce5bb82f03 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScalarXMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScalarXMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,7 +21,7 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.disposables.EmptyDisposable; -import io.reactivex.rxjava3.internal.fuseable.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueDisposable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScan.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScan.java index bd0ba2b12ae..59a74661cc6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScan.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScan.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScanSeed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScanSeed.java index 89eb4046f0b..f0e197db7ea 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScanSeed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScanSeed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.core.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSequenceEqual.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSequenceEqual.java index 11eb6946968..e79f992243c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSequenceEqual.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSequenceEqual.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,7 +20,7 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.BiPredicate; import io.reactivex.rxjava3.internal.disposables.ArrayCompositeDisposable; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; public final class ObservableSequenceEqual extends Observable { final ObservableSource first; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSequenceEqualSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSequenceEqualSingle.java index 9169cb64656..9b51815ce0e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSequenceEqualSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSequenceEqualSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,7 +21,7 @@ import io.reactivex.rxjava3.functions.BiPredicate; import io.reactivex.rxjava3.internal.disposables.ArrayCompositeDisposable; import io.reactivex.rxjava3.internal.fuseable.FuseToObservable; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class ObservableSequenceEqualSingle extends Single implements FuseToObservable { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSerialized.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSerialized.java index 98f757e6f72..c57d0d9a24e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSerialized.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSerialized.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.core.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSingleMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSingleMaybe.java index 83a8569f059..b4068e834d5 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSingleMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSingleMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSingleSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSingleSingle.java index de4729f5e53..dd8032a400e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSingleSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSingleSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkip.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkip.java index e0000dc7a5f..0fe5787c1be 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkip.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkip.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLast.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLast.java index 3e45e38a795..68fabb3ac7d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLast.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLast.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLastTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLastTimed.java index f70620b5c03..7cc6f34f24a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLastTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLastTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,7 +19,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; public final class ObservableSkipLastTimed extends AbstractObservableWithUpstream { final long time; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipUntil.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipUntil.java index 457158200dd..87535fabf22 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipUntil.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipUntil.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipWhile.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipWhile.java index d6dad232b58..1614b0b472b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipWhile.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipWhile.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSubscribeOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSubscribeOn.java index 8eac3ae04ed..5eaeaa50356 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSubscribeOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSubscribeOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchIfEmpty.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchIfEmpty.java index b697afc1c9b..6aa1d84ecfb 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchIfEmpty.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchIfEmpty.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchMap.java index e533834541e..3e0558aacf1 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,9 +21,10 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.AtomicThrowable; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class ObservableSwitchMap extends AbstractObservableWithUpstream { @@ -169,12 +170,9 @@ public boolean isDisposed() { @SuppressWarnings("unchecked") void disposeInner() { - SwitchMapInnerObserver a = active.get(); - if (a != CANCELLED) { - a = active.getAndSet((SwitchMapInnerObserver)CANCELLED); - if (a != CANCELLED && a != null) { - a.cancel(); - } + SwitchMapInnerObserver a = active.getAndSet((SwitchMapInnerObserver)CANCELLED); + if (a != null) { + a.cancel(); } } @@ -226,25 +224,6 @@ void drain() { SimpleQueue q = inner.queue; if (q != null) { - if (inner.done) { - boolean empty = q.isEmpty(); - if (delayErrors) { - if (empty) { - active.compareAndSet(inner, null); - continue; - } - } else { - Throwable ex = errors.get(); - if (ex != null) { - errors.tryTerminateConsumer(a); - return; - } - if (empty) { - active.compareAndSet(inner, null); - continue; - } - } - } boolean retry = false; @@ -370,9 +349,10 @@ public void onSubscribe(Disposable d) { @Override public void onNext(R t) { - if (index == parent.unique) { + SimpleQueue q = queue; + if (index == parent.unique && q != null) { if (t != null) { - queue.offer(t); + q.offer(t); } parent.drain(); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTake.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTake.java index 63f37db46e4..8cc73b1b565 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTake.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTake.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLast.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLast.java index bfa2ee0bdda..b0b04c141d2 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLast.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLast.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -77,9 +77,7 @@ public void onComplete() { } T v = poll(); if (v == null) { - if (!cancelled) { - a.onComplete(); - } + a.onComplete(); return; } a.onNext(v); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastOne.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastOne.java index f2766db765f..cb243dd3bdf 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastOne.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastOne.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import io.reactivex.rxjava3.core.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastTimed.java index be6f83db79e..33066f374b8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,7 +19,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; public final class ObservableTakeLastTimed extends AbstractObservableWithUpstream { final long count; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntil.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntil.java index f1d5d00a0d0..c32f3a6f654 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntil.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntil.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntilPredicate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntilPredicate.java index 1727a24fb48..5183a6026e5 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntilPredicate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntilPredicate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeWhile.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeWhile.java index 5c251c969e8..1b56e6cf34d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeWhile.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeWhile.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleFirstTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleFirstTimed.java index 041ce808405..6bf3b9f119c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleFirstTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleFirstTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,28 +19,36 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Scheduler.Worker; import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.Consumer; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; import io.reactivex.rxjava3.observers.SerializedObserver; -import io.reactivex.rxjava3.plugins.RxJavaPlugins; public final class ObservableThrottleFirstTimed extends AbstractObservableWithUpstream { final long timeout; final TimeUnit unit; final Scheduler scheduler; - - public ObservableThrottleFirstTimed(ObservableSource source, - long timeout, TimeUnit unit, Scheduler scheduler) { + final Consumer onDropped; + + public ObservableThrottleFirstTimed( + ObservableSource source, + long timeout, + TimeUnit unit, + Scheduler scheduler, + Consumer onDropped) { super(source); this.timeout = timeout; this.unit = unit; this.scheduler = scheduler; + this.onDropped = onDropped; } @Override public void subscribeActual(Observer t) { source.subscribe(new DebounceTimedObserver<>( new SerializedObserver<>(t), - timeout, unit, scheduler.createWorker())); + timeout, unit, scheduler.createWorker(), + onDropped)); } static final class DebounceTimedObserver @@ -52,18 +60,21 @@ static final class DebounceTimedObserver final long timeout; final TimeUnit unit; final Scheduler.Worker worker; - + final Consumer onDropped; Disposable upstream; - volatile boolean gate; - boolean done; - - DebounceTimedObserver(Observer actual, long timeout, TimeUnit unit, Worker worker) { + DebounceTimedObserver( + Observer actual, + long timeout, + TimeUnit unit, + Worker worker, + Consumer onDropped) { this.downstream = actual; this.timeout = timeout; this.unit = unit; this.worker = worker; + this.onDropped = onDropped; } @Override @@ -76,7 +87,7 @@ public void onSubscribe(Disposable d) { @Override public void onNext(T t) { - if (!gate && !done) { + if (!gate) { gate = true; downstream.onNext(t); @@ -86,6 +97,15 @@ public void onNext(T t) { d.dispose(); } DisposableHelper.replace(this, worker.schedule(this, timeout, unit)); + } else if (onDropped != null) { + try { + onDropped.accept(t); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.dispose(); + downstream.onError(ex); + worker.dispose(); + } } } @@ -96,22 +116,14 @@ public void run() { @Override public void onError(Throwable t) { - if (done) { - RxJavaPlugins.onError(t); - } else { - done = true; - downstream.onError(t); - worker.dispose(); - } + downstream.onError(t); + worker.dispose(); } @Override public void onComplete() { - if (!done) { - done = true; - downstream.onComplete(); - worker.dispose(); - } + downstream.onComplete(); + worker.dispose(); } @Override diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleLatest.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleLatest.java index 253f5d35013..caf14d3a5e1 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleLatest.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleLatest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,7 +18,10 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.functions.Consumer; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** * Emits the next or latest item when the given time elapses. @@ -41,19 +44,24 @@ public final class ObservableThrottleLatest extends AbstractObservableWithUps final boolean emitLast; + final Consumer onDropped; + public ObservableThrottleLatest(Observable source, - long timeout, TimeUnit unit, Scheduler scheduler, - boolean emitLast) { + long timeout, TimeUnit unit, + Scheduler scheduler, + boolean emitLast, + Consumer onDropped) { super(source); this.timeout = timeout; this.unit = unit; this.scheduler = scheduler; this.emitLast = emitLast; + this.onDropped = onDropped; } @Override protected void subscribeActual(Observer observer) { - source.subscribe(new ThrottleLatestObserver<>(observer, timeout, unit, scheduler.createWorker(), emitLast)); + source.subscribe(new ThrottleLatestObserver<>(observer, timeout, unit, scheduler.createWorker(), emitLast, onDropped)); } static final class ThrottleLatestObserver @@ -74,6 +82,8 @@ static final class ThrottleLatestObserver final AtomicReference latest; + final Consumer onDropped; + Disposable upstream; volatile boolean done; @@ -86,14 +96,17 @@ static final class ThrottleLatestObserver boolean timerRunning; ThrottleLatestObserver(Observer downstream, - long timeout, TimeUnit unit, Scheduler.Worker worker, - boolean emitLast) { + long timeout, TimeUnit unit, + Scheduler.Worker worker, + boolean emitLast, + Consumer onDropped) { this.downstream = downstream; this.timeout = timeout; this.unit = unit; this.worker = worker; this.emitLast = emitLast; this.latest = new AtomicReference<>(); + this.onDropped = onDropped; } @Override @@ -106,7 +119,17 @@ public void onSubscribe(Disposable d) { @Override public void onNext(T t) { - latest.set(t); + T old = latest.getAndSet(t); + if (onDropped != null && old != null) { + try { + onDropped.accept(old); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + upstream.dispose(); + error = ex; + done = true; + } + } drain(); } @@ -129,6 +152,22 @@ public void dispose() { upstream.dispose(); worker.dispose(); if (getAndIncrement() == 0) { + clear(); + } + } + + void clear() { + if (onDropped != null) { + T v = latest.getAndSet(null); + if (v != null) { + try { + onDropped.accept(v); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + RxJavaPlugins.onError(ex); + } + } + } else { latest.lazySet(null); } } @@ -158,14 +197,27 @@ void drain() { for (;;) { if (cancelled) { - latest.lazySet(null); + clear(); return; } boolean d = done; + Throwable error = this.error; if (d && error != null) { - latest.lazySet(null); + if (onDropped != null) { + T v = latest.getAndSet(null); + if (v != null) { + try { + onDropped.accept(v); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + error = new CompositeException(error, ex); + } + } + } else { + latest.lazySet(null); + } downstream.onError(error); worker.dispose(); return; @@ -175,9 +227,22 @@ void drain() { boolean empty = v == null; if (d) { - v = latest.getAndSet(null); - if (!empty && emitLast) { - downstream.onNext(v); + if (!empty) { + v = latest.getAndSet(null); + if (emitLast) { + downstream.onNext(v); + } else { + if (onDropped != null) { + try { + onDropped.accept(v); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + downstream.onError(ex); + worker.dispose(); + return; + } + } + } } downstream.onComplete(); worker.dispose(); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeInterval.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeInterval.java index 7dd47ec03bb..4a4e6a787f1 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeInterval.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeInterval.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeout.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeout.java index dfef0e74e6d..1922251d54a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeout.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeout.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeoutTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeoutTimed.java index 29b17729305..d0f56951432 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeoutTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeoutTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimer.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimer.java index 778388f39b3..3c9500996e6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToList.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToList.java index 6a3c5322f21..e75986c77cb 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToList.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToList.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,7 +20,6 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Supplier; import io.reactivex.rxjava3.internal.disposables.*; -import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.internal.util.ExceptionHelper; public final class ObservableToList> @@ -28,12 +27,6 @@ public final class ObservableToList> final Supplier collectionSupplier; - @SuppressWarnings({ "unchecked", "rawtypes" }) - public ObservableToList(ObservableSource source, final int defaultCapacityHint) { - super(source); - this.collectionSupplier = (Supplier)Functions.createArrayList(defaultCapacityHint); - } - public ObservableToList(ObservableSource source, Supplier collectionSupplier) { super(source); this.collectionSupplier = collectionSupplier; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToListSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToListSingle.java index 0ac41b12d61..de4db3ecf1b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToListSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToListSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUnsubscribeOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUnsubscribeOn.java index 2c5f748477d..d06d64f34c5 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUnsubscribeOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUnsubscribeOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUsing.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUsing.java index dec3da5ebe6..1ffdef32d6e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUsing.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUsing.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -115,11 +115,9 @@ public void onError(Throwable t) { } } - upstream.dispose(); downstream.onError(t); } else { downstream.onError(t); - upstream.dispose(); disposeResource(); } } @@ -137,11 +135,9 @@ public void onComplete() { } } - upstream.dispose(); downstream.onComplete(); } else { downstream.onComplete(); - upstream.dispose(); disposeResource(); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindow.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindow.java index 3ada9cd93c9..c742ad6288e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindow.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindow.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -51,18 +51,20 @@ static final class WindowExactObserver final long count; final int capacityHint; + final AtomicBoolean cancelled; + long size; Disposable upstream; UnicastSubject window; - volatile boolean cancelled; - WindowExactObserver(Observer> actual, long count, int capacityHint) { this.downstream = actual; this.count = count; this.capacityHint = capacityHint; + this.cancelled = new AtomicBoolean(); + this.lazySet(1); } @Override @@ -78,7 +80,9 @@ public void onSubscribe(Disposable d) { public void onNext(T t) { UnicastSubject w = window; ObservableWindowSubscribeIntercept intercept = null; - if (w == null && !cancelled) { + if (w == null && !cancelled.get()) { + getAndIncrement(); + w = UnicastSubject.create(capacityHint, this); window = w; intercept = new ObservableWindowSubscribeIntercept<>(w); @@ -92,15 +96,12 @@ public void onNext(T t) { size = 0; window = null; w.onComplete(); - if (cancelled) { - upstream.dispose(); - } } if (intercept != null && intercept.tryAbandon()) { + window = null; w.onComplete(); w = null; - window = null; } } } @@ -127,23 +128,25 @@ public void onComplete() { @Override public void dispose() { - cancelled = true; + if (cancelled.compareAndSet(false, true)) { + run(); + } } @Override public boolean isDisposed() { - return cancelled; + return cancelled.get(); } @Override public void run() { - if (cancelled) { + if (decrementAndGet() == 0) { upstream.dispose(); } } } - static final class WindowSkipObserver extends AtomicBoolean + static final class WindowSkipObserver extends AtomicInteger implements Observer, Disposable, Runnable { private static final long serialVersionUID = 3366976432059579510L; @@ -153,23 +156,23 @@ static final class WindowSkipObserver extends AtomicBoolean final int capacityHint; final ArrayDeque> windows; - long index; + final AtomicBoolean cancelled; - volatile boolean cancelled; + long index; /** Counts how many elements were emitted to the very first window in windows. */ long firstEmission; Disposable upstream; - final AtomicInteger wip = new AtomicInteger(); - WindowSkipObserver(Observer> actual, long count, long skip, int capacityHint) { this.downstream = actual; this.count = count; this.skip = skip; this.capacityHint = capacityHint; this.windows = new ArrayDeque<>(); + this.cancelled = new AtomicBoolean(); + this.lazySet(1); } @Override @@ -191,8 +194,8 @@ public void onNext(T t) { ObservableWindowSubscribeIntercept intercept = null; - if (i % s == 0 && !cancelled) { - wip.getAndIncrement(); + if (i % s == 0 && !cancelled.get()) { + getAndIncrement(); UnicastSubject w = UnicastSubject.create(capacityHint, this); intercept = new ObservableWindowSubscribeIntercept<>(w); ws.offer(w); @@ -207,8 +210,7 @@ public void onNext(T t) { if (c >= count) { ws.poll().onComplete(); - if (ws.isEmpty() && cancelled) { - this.upstream.dispose(); + if (ws.isEmpty() && cancelled.get()) { return; } firstEmission = c - s; @@ -243,20 +245,20 @@ public void onComplete() { @Override public void dispose() { - cancelled = true; + if (cancelled.compareAndSet(false, true)) { + run(); + } } @Override public boolean isDisposed() { - return cancelled; + return cancelled.get(); } @Override public void run() { - if (wip.decrementAndGet() == 0) { - if (cancelled) { - upstream.dispose(); - } + if (decrementAndGet() == 0) { + upstream.dispose(); } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowBoundary.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowBoundary.java index 503a5cbd295..a1ecb8e8690 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowBoundary.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowBoundary.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowBoundarySelector.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowBoundarySelector.java index 367ddf2d02f..cec435839e1 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowBoundarySelector.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowBoundarySelector.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,9 +23,9 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; import io.reactivex.rxjava3.internal.queue.MpscLinkedQueue; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimplePlainQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.subjects.UnicastSubject; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowSubscribeIntercept.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowSubscribeIntercept.java index da6f96f2a3e..4cc879662d4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowSubscribeIntercept.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowSubscribeIntercept.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -43,4 +43,4 @@ protected void subscribeActual(Observer s) { boolean tryAbandon() { return !once.get() && once.compareAndSet(false, true); } -} \ No newline at end of file +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowTimed.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowTimed.java index 5c295f46089..2cc96a61a93 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowTimed.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowTimed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,8 +23,8 @@ import io.reactivex.rxjava3.core.Scheduler.Worker; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.*; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; import io.reactivex.rxjava3.internal.queue.MpscLinkedQueue; +import io.reactivex.rxjava3.operators.SimplePlainQueue; import io.reactivex.rxjava3.subjects.UnicastSubject; public final class ObservableWindowTimed extends AbstractObservableWithUpstream> { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWithLatestFrom.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWithLatestFrom.java index b7e283c5156..95b21187a71 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWithLatestFrom.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWithLatestFrom.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWithLatestFromMany.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWithLatestFromMany.java index c9f2a6b57af..f8327b82846 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWithLatestFromMany.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWithLatestFromMany.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import java.util.Arrays; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZip.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZip.java index ace2d748e50..e1626b48656 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZip.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZip.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.disposables.*; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; public final class ObservableZip extends Observable { diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipIterable.java index d775c585157..7c8f5e6d0e5 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -112,7 +112,7 @@ public void onNext(T t) { u = Objects.requireNonNull(iterator.next(), "The iterator returned a null value"); } catch (Throwable e) { Exceptions.throwIfFatal(e); - error(e); + fail(e); return; } @@ -121,7 +121,7 @@ public void onNext(T t) { v = Objects.requireNonNull(zipper.apply(t, u), "The zipper function returned a null value"); } catch (Throwable e) { Exceptions.throwIfFatal(e); - error(e); + fail(e); return; } @@ -133,7 +133,7 @@ public void onNext(T t) { b = iterator.hasNext(); } catch (Throwable e) { Exceptions.throwIfFatal(e); - error(e); + fail(e); return; } @@ -144,7 +144,7 @@ public void onNext(T t) { } } - void error(Throwable e) { + void fail(Throwable e) { done = true; upstream.dispose(); downstream.onError(e); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObserverResourceWrapper.java b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObserverResourceWrapper.java index 4245417ce78..a3c797fee63 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObserverResourceWrapper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/observable/ObserverResourceWrapper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelCollect.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelCollect.java index 29f9d916749..60e36beed44 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelCollect.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelCollect.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -47,6 +47,8 @@ public ParallelCollect(ParallelFlowable source, @Override public void subscribe(Subscriber[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelConcatMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelConcatMap.java index 1ff745ecba9..ebdcf0bdf3b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelConcatMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelConcatMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,6 +19,7 @@ import io.reactivex.rxjava3.internal.operators.flowable.FlowableConcatMap; import io.reactivex.rxjava3.internal.util.ErrorMode; import io.reactivex.rxjava3.parallel.ParallelFlowable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; import java.util.Objects; @@ -55,6 +56,8 @@ public int parallelism() { @Override public void subscribe(Subscriber[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelDoOnNextTry.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelDoOnNextTry.java index 6b3f69ff978..b8ff3885355 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelDoOnNextTry.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelDoOnNextTry.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,8 +17,8 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; import io.reactivex.rxjava3.parallel.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; @@ -48,6 +48,8 @@ public ParallelDoOnNextTry(ParallelFlowable source, Consumer onNex @Override public void subscribe(Subscriber[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFilter.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFilter.java index 14f414dce3f..28987a6fc9c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFilter.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFilter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,8 +17,8 @@ import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Predicate; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; import io.reactivex.rxjava3.parallel.ParallelFlowable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; @@ -40,6 +40,8 @@ public ParallelFilter(ParallelFlowable source, Predicate predicate @Override public void subscribe(Subscriber[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFilterTry.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFilterTry.java index bfd22ec5a85..563937e1a63 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFilterTry.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFilterTry.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,8 +17,8 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; import io.reactivex.rxjava3.parallel.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; @@ -46,6 +46,8 @@ public ParallelFilterTry(ParallelFlowable source, Predicate predic @Override public void subscribe(Subscriber[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFlatMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFlatMap.java index 1e0c9f5738d..227521143a2 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFlatMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFlatMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,6 +18,7 @@ import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.operators.flowable.FlowableFlatMap; import io.reactivex.rxjava3.parallel.ParallelFlowable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** * Flattens the generated Publishers on each rail. @@ -57,6 +58,8 @@ public int parallelism() { @Override public void subscribe(Subscriber[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFlatMapIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFlatMapIterable.java index 1bb127233f2..9e6c45a9ca5 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFlatMapIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFlatMapIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,6 +18,7 @@ import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.operators.flowable.FlowableFlattenIterable; import io.reactivex.rxjava3.parallel.ParallelFlowable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** * Flattens the generated {@link Iterable}s on each rail. @@ -50,6 +51,8 @@ public int parallelism() { @Override public void subscribe(Subscriber[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFromArray.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFromArray.java index cb40caaad59..d2512ccd7f1 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFromArray.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFromArray.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,6 +16,7 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.parallel.ParallelFlowable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** * Wraps multiple Publishers into a ParallelFlowable which runs them @@ -37,6 +38,8 @@ public int parallelism() { @Override public void subscribe(Subscriber[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFromPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFromPublisher.java index 0d4fb9a4c55..eb57bccea5d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFromPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelFromPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,11 +19,13 @@ import io.reactivex.rxjava3.core.FlowableSubscriber; import io.reactivex.rxjava3.exceptions.*; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; import io.reactivex.rxjava3.parallel.ParallelFlowable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** * Dispatches the values from upstream in a round robin fashion to subscribers which are @@ -51,6 +53,8 @@ public int parallelism() { @Override public void subscribe(Subscriber[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } @@ -150,10 +154,6 @@ void setupSubscribers() { final int m = subs.length; for (int i = 0; i < m; i++) { - if (cancelled) { - return; - } - subscriberCount.lazySet(i + 1); subs[i].onSubscribe(new RailSubscription(i, m)); @@ -204,7 +204,7 @@ public void onNext(T t) { if (sourceMode == QueueSubscription.NONE) { if (!queue.offer(t)) { upstream.cancel(); - onError(new MissingBackpressureException("Queue is full?")); + onError(new QueueOverflowException()); return; } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelJoin.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelJoin.java index 4545b133f5b..2852fda8c7f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelJoin.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelJoin.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,11 +18,12 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.exceptions.MissingBackpressureException; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; +import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimplePlainQueue; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscArrayQueue; import io.reactivex.rxjava3.parallel.ParallelFlowable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; @@ -152,7 +153,7 @@ public void onNext(JoinInnerSubscriber inner, T value) { if (!q.offer(value)) { cancelAll(); - Throwable mbe = new MissingBackpressureException("Queue full?!"); + Throwable mbe = new QueueOverflowException(); if (errors.compareAndSet(null, mbe)) { downstream.onError(mbe); } else { @@ -169,7 +170,7 @@ public void onNext(JoinInnerSubscriber inner, T value) { if (!q.offer(value)) { cancelAll(); - onError(new MissingBackpressureException("Queue full?!")); + onError(new QueueOverflowException()); return; } @@ -298,18 +299,13 @@ void drainLoop() { } } - if (e != 0 && r != Long.MAX_VALUE) { - requested.addAndGet(-e); + if (e != 0) { + BackpressureHelper.produced(requested, e); } - int w = get(); - if (w == missed) { - missed = addAndGet(-missed); - if (missed == 0) { - break; - } - } else { - missed = w; + missed = addAndGet(-missed); + if (missed == 0) { + break; } } } @@ -337,7 +333,7 @@ void onNext(JoinInnerSubscriber inner, T value) { if (!q.offer(value)) { inner.cancel(); - errors.tryAddThrowableOrReport(new MissingBackpressureException("Queue full?!")); + errors.tryAddThrowableOrReport(new QueueOverflowException()); done.decrementAndGet(); drainLoop(); return; @@ -350,10 +346,9 @@ void onNext(JoinInnerSubscriber inner, T value) { SimplePlainQueue q = inner.getQueue(); if (!q.offer(value)) { - if (inner.cancel()) { - errors.tryAddThrowableOrReport(new MissingBackpressureException("Queue full?!")); - done.decrementAndGet(); - } + inner.cancel(); + errors.tryAddThrowableOrReport(new QueueOverflowException()); + done.decrementAndGet(); } if (getAndIncrement() != 0) { @@ -464,18 +459,13 @@ void drainLoop() { } } - if (e != 0 && r != Long.MAX_VALUE) { - requested.addAndGet(-e); + if (e != 0) { + BackpressureHelper.produced(requested, e); } - int w = get(); - if (w == missed) { - missed = addAndGet(-missed); - if (missed == 0) { - break; - } - } else { - missed = w; + missed = addAndGet(-missed); + if (missed == 0) { + break; } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelMap.java index c9418878536..81d70a01d9e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,8 +18,8 @@ import io.reactivex.rxjava3.core.FlowableSubscriber; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; import io.reactivex.rxjava3.parallel.ParallelFlowable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; @@ -44,6 +44,8 @@ public ParallelMap(ParallelFlowable source, Function @Override public void subscribe(Subscriber[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelMapTry.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelMapTry.java index 30250f2e602..cac64f37114 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelMapTry.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelMapTry.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,8 +17,8 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; import io.reactivex.rxjava3.parallel.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; @@ -49,6 +49,8 @@ public ParallelMapTry(ParallelFlowable source, Function[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelPeek.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelPeek.java index 206a2dd4721..42f65567ca0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelPeek.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelPeek.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -66,6 +66,8 @@ public ParallelPeek(ParallelFlowable source, @Override public void subscribe(Subscriber[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelReduce.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelReduce.java index 53fa2b38992..b955ca711ae 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelReduce.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelReduce.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -46,6 +46,8 @@ public ParallelReduce(ParallelFlowable source, Supplier initialS @Override public void subscribe(Subscriber[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelReduceFull.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelReduceFull.java index a47bc5b8987..2e24b9e2562 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelReduceFull.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelReduceFull.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelRunOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelRunOn.java index ceb2a7665a2..22f822db34a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelRunOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelRunOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,13 +19,13 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Scheduler.Worker; -import io.reactivex.rxjava3.exceptions.MissingBackpressureException; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; +import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.internal.schedulers.SchedulerMultiWorkerSupport; import io.reactivex.rxjava3.internal.schedulers.SchedulerMultiWorkerSupport.WorkerCallback; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.BackpressureHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; +import io.reactivex.rxjava3.operators.SpscArrayQueue; import io.reactivex.rxjava3.parallel.ParallelFlowable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; @@ -49,7 +49,9 @@ public ParallelRunOn(ParallelFlowable parent, } @Override - public void subscribe(final Subscriber[] subscribers) { + public void subscribe(Subscriber[] subscribers) { + subscribers = RxJavaPlugins.onSubscribe(this, subscribers); + if (!validate(subscribers)) { return; } @@ -146,7 +148,7 @@ public final void onNext(T t) { } if (!queue.offer(t)) { upstream.cancel(); - onError(new MissingBackpressureException("Queue is full?!")); + onError(new QueueOverflowException()); return; } schedule(); @@ -430,19 +432,14 @@ public void run() { } } - if (e != 0L && r != Long.MAX_VALUE) { - requested.addAndGet(-e); + if (e != 0L) { + BackpressureHelper.produced(requested, e); } - int w = get(); - if (w == missed) { - consumed = c; - missed = addAndGet(-missed); - if (missed == 0) { - break; - } - } else { - missed = w; + consumed = c; + missed = addAndGet(-missed); + if (missed == 0) { + break; } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelSortedJoin.java b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelSortedJoin.java index 7994abf6976..fb20bb65b90 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelSortedJoin.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/parallel/ParallelSortedJoin.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -215,48 +215,41 @@ void drain() { e++; } - if (e == r) { - if (cancelled) { - Arrays.fill(lists, null); - return; - } + if (cancelled) { + Arrays.fill(lists, null); + return; + } - Throwable ex = error.get(); - if (ex != null) { - cancelAll(); - Arrays.fill(lists, null); - a.onError(ex); - return; - } + Throwable ex = error.get(); + if (ex != null) { + cancelAll(); + Arrays.fill(lists, null); + a.onError(ex); + return; + } - boolean empty = true; + boolean empty = true; - for (int i = 0; i < n; i++) { - if (indexes[i] != lists[i].size()) { - empty = false; - break; - } + for (int i = 0; i < n; i++) { + if (indexes[i] != lists[i].size()) { + empty = false; + break; } + } - if (empty) { - Arrays.fill(lists, null); - a.onComplete(); - return; - } + if (empty) { + Arrays.fill(lists, null); + a.onComplete(); + return; } - if (e != 0 && r != Long.MAX_VALUE) { - requested.addAndGet(-e); + if (e != 0) { + BackpressureHelper.produced(requested, e); } - int w = get(); - if (w == missed) { - missed = addAndGet(-missed); - if (missed == 0) { - break; - } - } else { - missed = w; + missed = addAndGet(-missed); + if (missed == 0) { + break; } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleAmb.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleAmb.java index 7fd1dba29f0..24ff7eabed4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleAmb.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleAmb.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleCache.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleCache.java index a8cb63f0eda..7f0848e4c1a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleCache.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleCache.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleContains.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleContains.java index aaa249a6e8f..2497fb2047a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleContains.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleContains.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleCreate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleCreate.java index 8c5331c87bd..c0f6c4b1d0b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleCreate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleCreate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDefer.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDefer.java index 24a35fbdee2..ddf2b2c3479 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDefer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDefer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelay.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelay.java index 12da3821fcb..1a92d389fad 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelay.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelay.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithCompletable.java index c3f74584595..164a5029928 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithObservable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithObservable.java index a0eb8ab860a..58ed261e714 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -56,7 +56,7 @@ static final class OtherSubscriber @Override public void onSubscribe(Disposable d) { - if (DisposableHelper.set(this, d)) { + if (DisposableHelper.setOnce(this, d)) { downstream.onSubscribe(this); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithPublisher.java index 1d8a601a024..12eeb7fd13d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithSingle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithSingle.java index d8e11665c89..1f2ffb21dde 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithSingle.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayWithSingle.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDematerialize.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDematerialize.java index 6d072f4ceaf..e573560e76c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDematerialize.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDematerialize.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDetach.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDetach.java index 72e1f3def34..2a9acc8a193 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDetach.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDetach.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterSuccess.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterSuccess.java index d7ab5e4c79b..51b73f0216b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterSuccess.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterSuccess.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterTerminate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterTerminate.java index eca7ebff151..651c9ee60d7 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterTerminate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterTerminate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoFinally.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoFinally.java index 0ba60a6493a..a64060cc977 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoFinally.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoFinally.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnDispose.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnDispose.java index 262f4f7d433..8c9fd1cb1b3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnDispose.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnDispose.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnError.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnError.java index 87061fdafe7..dd24ac210c9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnError.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnError.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnEvent.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnEvent.java index 9aa9fccd8ad..de53462380d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnEvent.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnEvent.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnLifecycle.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnLifecycle.java new file mode 100644 index 00000000000..2d4e15f27c5 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnLifecycle.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.disposables.*; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + +/** + * Invokes callbacks upon {@code onSubscribe} from upstream and + * {@code dispose} from downstream. + * + * @param the element type of the flow + * @since 3.0.0 + */ +public final class SingleDoOnLifecycle extends Single { + + final Single source; + + final Consumer onSubscribe; + + final Action onDispose; + + public SingleDoOnLifecycle(Single upstream, Consumer onSubscribe, + Action onDispose) { + this.source = upstream; + this.onSubscribe = onSubscribe; + this.onDispose = onDispose; + } + + @Override + protected void subscribeActual(SingleObserver observer) { + source.subscribe(new SingleLifecycleObserver<>(observer, onSubscribe, onDispose)); + } + + static final class SingleLifecycleObserver implements SingleObserver, Disposable { + + final SingleObserver downstream; + + final Consumer onSubscribe; + + final Action onDispose; + + Disposable upstream; + + SingleLifecycleObserver(SingleObserver downstream, Consumer onSubscribe, Action onDispose) { + this.downstream = downstream; + this.onSubscribe = onSubscribe; + this.onDispose = onDispose; + } + + @Override + public void onSubscribe(@NonNull Disposable d) { + // this way, multiple calls to onSubscribe can show up in tests that use doOnSubscribe to validate behavior + try { + onSubscribe.accept(d); + } catch (Throwable e) { + Exceptions.throwIfFatal(e); + d.dispose(); + this.upstream = DisposableHelper.DISPOSED; + EmptyDisposable.error(e, downstream); + return; + } + if (DisposableHelper.validate(this.upstream, d)) { + this.upstream = d; + downstream.onSubscribe(this); + } + } + + @Override + public void onSuccess(@NonNull T t) { + if (upstream != DisposableHelper.DISPOSED) { + upstream = DisposableHelper.DISPOSED; + downstream.onSuccess(t); + } + } + + @Override + public void onError(@NonNull Throwable e) { + if (upstream != DisposableHelper.DISPOSED) { + upstream = DisposableHelper.DISPOSED; + downstream.onError(e); + } else { + RxJavaPlugins.onError(e); + } + } + + @Override + public void dispose() { + try { + onDispose.run(); + } catch (Throwable e) { + Exceptions.throwIfFatal(e); + RxJavaPlugins.onError(e); + } + upstream.dispose(); + upstream = DisposableHelper.DISPOSED; + } + + @Override + public boolean isDisposed() { + return upstream.isDisposed(); + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnSubscribe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnSubscribe.java index 24a24caac93..567f95404b4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnSubscribe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnSubscribe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnSuccess.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnSuccess.java index 2efec6acdd7..855dc7e3884 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnSuccess.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnSuccess.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnTerminate.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnTerminate.java index 1bb0ca2decb..d6f5dea7fa3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnTerminate.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnTerminate.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleEquals.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleEquals.java index 0a839ab7470..d11f938a2ee 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleEquals.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleEquals.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -74,20 +74,13 @@ public void onSuccess(T value) { @Override public void onError(Throwable e) { - for (;;) { - int state = count.get(); - if (state >= 2) { - RxJavaPlugins.onError(e); - return; - } - if (count.compareAndSet(state, 2)) { - set.dispose(); - downstream.onError(e); - return; - } + int state = count.getAndSet(-1); + if (state == 0 || state == 1) { + set.dispose(); + downstream.onError(e); + } else { + RxJavaPlugins.onError(e); } } - } - } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleError.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleError.java index 89b9bc3baaa..f016d2c9a97 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleError.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleError.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMap.java index d622f83faee..ff38538b095 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapBiSelector.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapBiSelector.java new file mode 100644 index 00000000000..7f6f58de845 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapBiSelector.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.Exceptions; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.disposables.DisposableHelper; + +/** + * Maps a source item to another SingleSource then calls a BiFunction with the + * original item and the secondary item to generate the final result. + * + * @param the main value type + * @param the second value type + * @param the result value type + * @since 3.0.0 + */ +public final class SingleFlatMapBiSelector extends Single { + + final SingleSource source; + + final Function> mapper; + + final BiFunction resultSelector; + + public SingleFlatMapBiSelector(SingleSource source, + Function> mapper, + BiFunction resultSelector) { + this.source = source; + this.mapper = mapper; + this.resultSelector = resultSelector; + } + + @Override + protected void subscribeActual(SingleObserver observer) { + source.subscribe(new FlatMapBiMainObserver(observer, mapper, resultSelector)); + } + + static final class FlatMapBiMainObserver + implements SingleObserver, Disposable { + + final Function> mapper; + + final InnerObserver inner; + + FlatMapBiMainObserver(SingleObserver actual, + Function> mapper, + BiFunction resultSelector) { + this.inner = new InnerObserver<>(actual, resultSelector); + this.mapper = mapper; + } + + @Override + public void dispose() { + DisposableHelper.dispose(inner); + } + + @Override + public boolean isDisposed() { + return DisposableHelper.isDisposed(inner.get()); + } + + @Override + public void onSubscribe(Disposable d) { + if (DisposableHelper.setOnce(inner, d)) { + inner.downstream.onSubscribe(this); + } + } + + @Override + public void onSuccess(T value) { + SingleSource next; + + try { + next = Objects.requireNonNull(mapper.apply(value), "The mapper returned a null MaybeSource"); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + inner.downstream.onError(ex); + return; + } + + if (DisposableHelper.replace(inner, null)) { + inner.value = value; + next.subscribe(inner); + } + } + + @Override + public void onError(Throwable e) { + inner.downstream.onError(e); + } + + static final class InnerObserver + extends AtomicReference + implements SingleObserver { + + private static final long serialVersionUID = -2897979525538174559L; + + final SingleObserver downstream; + + final BiFunction resultSelector; + + T value; + + InnerObserver(SingleObserver actual, + BiFunction resultSelector) { + this.downstream = actual; + this.resultSelector = resultSelector; + } + + @Override + public void onSubscribe(Disposable d) { + DisposableHelper.setOnce(this, d); + } + + @Override + public void onSuccess(U value) { + T t = this.value; + this.value = null; + + R r; + + try { + r = Objects.requireNonNull(resultSelector.apply(t, value), "The resultSelector returned a null value"); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + downstream.onError(ex); + return; + } + + downstream.onSuccess(r); + } + + @Override + public void onError(Throwable e) { + downstream.onError(e); + } + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapCompletable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapCompletable.java index d914799640d..a06241c56c9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapCompletable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapCompletable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableFlowable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableFlowable.java index 9e05a25ef89..6d697265888 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableFlowable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableFlowable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -154,7 +154,7 @@ void drain() { long e = 0L; if (r == Long.MAX_VALUE) { - slowPath(a, iterator); + fastPath(a, iterator); return; } @@ -213,7 +213,7 @@ void drain() { } } - void slowPath(Subscriber a, Iterator iterator) { + void fastPath(Subscriber a, Iterator iterator) { for (;;) { if (cancelled) { return; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableObservable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableObservable.java index add137d7cb5..c07131da8c7 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapMaybe.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapMaybe.java index d810f8f5c3d..c58e6aeeae9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapMaybe.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapMaybe.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapNotification.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapNotification.java new file mode 100644 index 00000000000..bb592a74a9e --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapNotification.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.disposables.DisposableHelper; + +/** + * Maps a value into a SingleSource and relays its signal. + * + * @param the source value type + * @param the result value type + * @since 3.0.0 + */ +public final class SingleFlatMapNotification extends Single { + + final SingleSource source; + + final Function> onSuccessMapper; + + final Function> onErrorMapper; + + public SingleFlatMapNotification(SingleSource source, + Function> onSuccessMapper, + Function> onErrorMapper) { + this.source = source; + this.onSuccessMapper = onSuccessMapper; + this.onErrorMapper = onErrorMapper; + } + + @Override + protected void subscribeActual(SingleObserver observer) { + source.subscribe(new FlatMapSingleObserver<>(observer, onSuccessMapper, onErrorMapper)); + } + + static final class FlatMapSingleObserver + extends AtomicReference + implements SingleObserver, Disposable { + + private static final long serialVersionUID = 4375739915521278546L; + + final SingleObserver downstream; + + final Function> onSuccessMapper; + + final Function> onErrorMapper; + + Disposable upstream; + + FlatMapSingleObserver(SingleObserver actual, + Function> onSuccessMapper, + Function> onErrorMapper) { + this.downstream = actual; + this.onSuccessMapper = onSuccessMapper; + this.onErrorMapper = onErrorMapper; + } + + @Override + public void dispose() { + DisposableHelper.dispose(this); + upstream.dispose(); + } + + @Override + public boolean isDisposed() { + return DisposableHelper.isDisposed(get()); + } + + @Override + public void onSubscribe(Disposable d) { + if (DisposableHelper.validate(this.upstream, d)) { + this.upstream = d; + + downstream.onSubscribe(this); + } + } + + @Override + public void onSuccess(T value) { + SingleSource source; + + try { + source = Objects.requireNonNull(onSuccessMapper.apply(value), "The onSuccessMapper returned a null SingleSource"); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + downstream.onError(ex); + return; + } + + if (!isDisposed()) { + source.subscribe(new InnerObserver()); + } + } + + @Override + public void onError(Throwable e) { + SingleSource source; + + try { + source = Objects.requireNonNull(onErrorMapper.apply(e), "The onErrorMapper returned a null SingleSource"); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + downstream.onError(new CompositeException(e, ex)); + return; + } + + if (!isDisposed()) { + source.subscribe(new InnerObserver()); + } + } + + final class InnerObserver implements SingleObserver { + + @Override + public void onSubscribe(Disposable d) { + DisposableHelper.setOnce(FlatMapSingleObserver.this, d); + } + + @Override + public void onSuccess(R value) { + downstream.onSuccess(value); + } + + @Override + public void onError(Throwable e) { + downstream.onError(e); + } + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapPublisher.java index f474830e403..59a067832fe 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -28,7 +28,7 @@ * A Flowable that emits items based on applying a specified function to the item emitted by the * source Single, where that function returns a Publisher. *

- * + * *

*
Backpressure:
*
The returned {@code Flowable} honors the backpressure of the downstream consumer @@ -92,7 +92,9 @@ public void onSuccess(S value) { downstream.onError(e); return; } - f.subscribe(this); + if (parent.get() != SubscriptionHelper.CANCELLED) { + f.subscribe(this); + } } @Override diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromCallable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromCallable.java index a78dde3e36d..d1a6b73384b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromCallable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromCallable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromPublisher.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromPublisher.java index e18394eb1a5..860e47f9041 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromPublisher.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromPublisher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromSupplier.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromSupplier.java index e6fd32603f3..83e2dc47804 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromSupplier.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromSupplier.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromUnsafeSource.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromUnsafeSource.java index 328ab873b6c..e09e38c8335 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromUnsafeSource.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleFromUnsafeSource.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleHide.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleHide.java index 34f5dc4aed7..01a4e36d6e2 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleHide.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleHide.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleInternalHelper.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleInternalHelper.java index 95ed46144c8..5df3dae35df 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleInternalHelper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleInternalHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,12 +14,10 @@ package io.reactivex.rxjava3.internal.operators.single; import java.util.*; -import java.util.concurrent.Callable; import org.reactivestreams.Publisher; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.functions.*; /** @@ -32,14 +30,9 @@ private SingleInternalHelper() { throw new IllegalStateException("No instances!"); } - enum NoSuchElementCallable implements Supplier, Callable { + enum NoSuchElementSupplier implements Supplier { INSTANCE; - @Override - public NoSuchElementException call() { - return new NoSuchElementException(); - } - @Override public NoSuchElementException get() { return new NoSuchElementException(); @@ -47,7 +40,7 @@ public NoSuchElementException get() { } public static Supplier emptyThrower() { - return NoSuchElementCallable.INSTANCE; + return NoSuchElementSupplier.INSTANCE; } @SuppressWarnings("rawtypes") @@ -105,19 +98,4 @@ public Iterator> iterator() { public static Iterable> iterableToFlowable(final Iterable> sources) { return new ToFlowableIterable<>(sources); } - - @SuppressWarnings("rawtypes") - enum ToObservable implements Function { - INSTANCE; - @SuppressWarnings("unchecked") - @Override - public Observable apply(SingleSource v) { - return new SingleToObservable(v); - } - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public static Function, Observable> toObservable() { - return (Function)ToObservable.INSTANCE; - } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleJust.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleJust.java index 4fd2387f960..ceb94b93a14 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleJust.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleJust.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleLift.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleLift.java index 8382b2f1b82..5b127e58cb4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleLift.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleLift.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleMap.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleMap.java index 534b41495c5..3fb20516ce0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleMap.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleMap.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleMaterialize.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleMaterialize.java index 1ffbfe073a2..c09d28ffd17 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleMaterialize.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleMaterialize.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleNever.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleNever.java index ea76fac50de..0feefe196d9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleNever.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleNever.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleObserveOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleObserveOn.java index 168a88ee8ec..e513e16fa26 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleObserveOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleObserveOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorComplete.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorComplete.java new file mode 100644 index 00000000000..bd083cddb18 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorComplete.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.functions.Predicate; +import io.reactivex.rxjava3.internal.operators.maybe.MaybeOnErrorComplete; + +/** + * Emits an onComplete if the source emits an onError and the predicate returns true for + * that Throwable. + * + * @param the value type + * @since 3.0.0 + */ +public final class SingleOnErrorComplete extends Maybe { + + final Single source; + + final Predicate predicate; + + public SingleOnErrorComplete(Single source, + Predicate predicate) { + this.source = source; + this.predicate = predicate; + } + + @Override + protected void subscribeActual(MaybeObserver observer) { + source.subscribe(new MaybeOnErrorComplete.OnErrorCompleteMultiObserver(observer, predicate)); + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn.java index 1a606d27500..d1f8b66fd91 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorReturn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleResumeNext.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleResumeNext.java index 070b2447474..554a2a254b6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleResumeNext.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleResumeNext.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleSubscribeOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleSubscribeOn.java index 3347fc19894..56cf684e9f4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleSubscribeOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleSubscribeOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTakeUntil.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTakeUntil.java index 50e8b897636..fb5d0989f66 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTakeUntil.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTakeUntil.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeInterval.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeInterval.java new file mode 100644 index 00000000000..f6d65f7c148 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeInterval.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.internal.disposables.DisposableHelper; +import io.reactivex.rxjava3.schedulers.Timed; + +/** + * Measures the time between subscription and the success item emission + * from the upstream and emits this as a {@link Timed} success value. + * @param the element type of the sequence + * @since 3.0.0 + */ +public final class SingleTimeInterval extends Single> { + + final SingleSource source; + + final TimeUnit unit; + + final Scheduler scheduler; + + final boolean start; + + public SingleTimeInterval(SingleSource source, TimeUnit unit, Scheduler scheduler, boolean start) { + this.source = source; + this.unit = unit; + this.scheduler = scheduler; + this.start = start; + } + + @Override + protected void subscribeActual(@NonNull SingleObserver> observer) { + source.subscribe(new TimeIntervalSingleObserver<>(observer, unit, scheduler, start)); + } + + static final class TimeIntervalSingleObserver implements SingleObserver, Disposable { + + final SingleObserver> downstream; + + final TimeUnit unit; + + final Scheduler scheduler; + + final long startTime; + + Disposable upstream; + + TimeIntervalSingleObserver(SingleObserver> downstream, TimeUnit unit, Scheduler scheduler, boolean start) { + this.downstream = downstream; + this.unit = unit; + this.scheduler = scheduler; + this.startTime = start ? scheduler.now(unit) : 0L; + } + + @Override + public void onSubscribe(@NonNull Disposable d) { + if (DisposableHelper.validate(this.upstream, d)) { + this.upstream = d; + + downstream.onSubscribe(this); + } + } + + @Override + public void onSuccess(@NonNull T t) { + downstream.onSuccess(new Timed<>(t, scheduler.now(unit) - startTime, unit)); + } + + @Override + public void onError(@NonNull Throwable e) { + downstream.onError(e); + } + + @Override + public void dispose() { + upstream.dispose(); + } + + @Override + public boolean isDisposed() { + return upstream.isDisposed(); + } + } +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeout.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeout.java index f529d02446a..cc5b9237277 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeout.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeout.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -113,11 +113,7 @@ public void onError(Throwable e) { @Override public void run() { - Disposable d = get(); - if (d != DisposableHelper.DISPOSED && compareAndSet(d, DisposableHelper.DISPOSED)) { - if (d != null) { - d.dispose(); - } + if (DisposableHelper.dispose(this)) { SingleSource other = this.other; if (other == null) { downstream.onError(new TimeoutException(timeoutMessage(timeout, unit))); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTimer.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTimer.java index 5188f3a2c91..07748952c85 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTimer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleTimer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleToFlowable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleToFlowable.java index 890f6b05692..e692dea5b96 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleToFlowable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleToFlowable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.single; import org.reactivestreams.Subscriber; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleToObservable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleToObservable.java index 810adaea3f6..45863177401 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleToObservable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleToObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.single; import io.reactivex.rxjava3.core.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleUnsubscribeOn.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleUnsubscribeOn.java index 9a78d61bb70..4b18599c84d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleUnsubscribeOn.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleUnsubscribeOn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleUsing.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleUsing.java index 57f9daf263c..55ab6c31ff0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleUsing.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleUsing.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleZipArray.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleZipArray.java index 9130a2bf356..b53d2f21844 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleZipArray.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleZipArray.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -74,7 +74,7 @@ static final class ZipCoordinator extends AtomicInteger implements Disposa final ZipSingleObserver[] observers; - final Object[] values; + Object[] values; @SuppressWarnings("unchecked") ZipCoordinator(SingleObserver observer, int n, Function zipper) { @@ -100,11 +100,16 @@ public void dispose() { for (ZipSingleObserver d : observers) { d.dispose(); } + + values = null; } } void innerSuccess(T value, int index) { - values[index] = value; + Object[] values = this.values; + if (values != null) { + values[index] = value; + } if (decrementAndGet() == 0) { R v; @@ -112,10 +117,12 @@ void innerSuccess(T value, int index) { v = Objects.requireNonNull(zipper.apply(values), "The zipper returned a null value"); } catch (Throwable ex) { Exceptions.throwIfFatal(ex); + this.values = null; downstream.onError(ex); return; } + this.values = null; downstream.onSuccess(v); } } @@ -134,6 +141,7 @@ void disposeExcept(int index) { void innerError(Throwable ex, int index) { if (getAndSet(0) > 0) { disposeExcept(index); + values = null; downstream.onError(ex); } else { RxJavaPlugins.onError(ex); diff --git a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleZipIterable.java b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleZipIterable.java index ad393987be8..935550ab479 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleZipIterable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/operators/single/SingleZipIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/queue/MpscLinkedQueue.java b/src/main/java/io/reactivex/rxjava3/internal/queue/MpscLinkedQueue.java index 31fe6eca9b1..e8d19c633e3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/queue/MpscLinkedQueue.java +++ b/src/main/java/io/reactivex/rxjava3/internal/queue/MpscLinkedQueue.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,7 +21,7 @@ import java.util.concurrent.atomic.AtomicReference; import io.reactivex.rxjava3.annotations.Nullable; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; +import io.reactivex.rxjava3.operators.SimplePlainQueue; /** * A multi-producer single consumer unbounded queue. @@ -91,6 +91,8 @@ public T poll() { // we have to null out the value because we are going to hang on to the node final T nextValue = nextNode.getAndNullValue(); spConsumerNode(nextNode); + // unlink previous consumer to help gc + currConsumerNode.soNext(null); return nextValue; } else if (currConsumerNode != lvProducerNode()) { @@ -101,6 +103,8 @@ else if (currConsumerNode != lvProducerNode()) { // we have to null out the value because we are going to hang on to the node final T nextValue = nextNode.getAndNullValue(); spConsumerNode(nextNode); + // unlink previous consumer to help gc + currConsumerNode.soNext(null); return nextValue; } return null; diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/AbstractDirectTask.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/AbstractDirectTask.java index a1c4bc2ce17..556fcd23c7b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/AbstractDirectTask.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/AbstractDirectTask.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.schedulers; @@ -35,14 +32,17 @@ abstract class AbstractDirectTask protected final Runnable runnable; + protected final boolean interruptOnCancel; + protected Thread runner; protected static final FutureTask FINISHED = new FutureTask<>(Functions.EMPTY_RUNNABLE, null); protected static final FutureTask DISPOSED = new FutureTask<>(Functions.EMPTY_RUNNABLE, null); - AbstractDirectTask(Runnable runnable) { + AbstractDirectTask(Runnable runnable, boolean interruptOnCancel) { this.runnable = runnable; + this.interruptOnCancel = interruptOnCancel; } @Override @@ -51,7 +51,7 @@ public final void dispose() { if (f != FINISHED && f != DISPOSED) { if (compareAndSet(f, DISPOSED)) { if (f != null) { - f.cancel(runner != Thread.currentThread()); + cancelFuture(f); } } } @@ -70,7 +70,7 @@ public final void setFuture(Future future) { break; } if (f == DISPOSED) { - future.cancel(runner != Thread.currentThread()); + cancelFuture(future); break; } if (compareAndSet(f, future)) { @@ -79,8 +79,36 @@ public final void setFuture(Future future) { } } + private void cancelFuture(Future future) { + if (runner == Thread.currentThread()) { + future.cancel(false); + } else { + future.cancel(interruptOnCancel); + } + } + @Override public Runnable getWrappedRunnable() { return runnable; } + + @Override + public String toString() { + String status; + Future f = get(); + if (f == FINISHED) { + status = "Finished"; + } else if (f == DISPOSED) { + status = "Disposed"; + } else { + Thread r = runner; + if (r != null) { + status = "Running on " + runner; + } else { + status = "Waiting"; + } + } + + return getClass().getSimpleName() + "[" + status + "]"; + } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/ComputationScheduler.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/ComputationScheduler.java index e0bf388772d..f6845e660e7 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/ComputationScheduler.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/ComputationScheduler.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.schedulers; import java.util.concurrent.*; @@ -175,15 +173,9 @@ public void start() { @Override public void shutdown() { - for (;;) { - FixedSchedulerPool curr = pool.get(); - if (curr == NONE) { - return; - } - if (pool.compareAndSet(curr, NONE)) { - curr.shutdown(); - return; - } + FixedSchedulerPool curr = pool.getAndSet(NONE); + if (curr != NONE) { + curr.shutdown(); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/DisposeOnCancel.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/DisposeOnCancel.java index 370fb5d8a2f..72ac8ef5251 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/DisposeOnCancel.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/DisposeOnCancel.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/ExecutorScheduler.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/ExecutorScheduler.java index a9547e64e1b..fa0bcab7f86 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/ExecutorScheduler.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/ExecutorScheduler.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -38,7 +38,9 @@ public final class ExecutorScheduler extends Scheduler { @NonNull final Executor executor; - static final Scheduler HELPER = Schedulers.single(); + static final class SingleHolder { + static final Scheduler HELPER = Schedulers.single(); + } public ExecutorScheduler(@NonNull Executor executor, boolean interruptibleWorker, boolean fair) { this.executor = executor; @@ -58,7 +60,7 @@ public Disposable scheduleDirect(@NonNull Runnable run) { Runnable decoratedRun = RxJavaPlugins.onSchedule(run); try { if (executor instanceof ExecutorService) { - ScheduledDirectTask task = new ScheduledDirectTask(decoratedRun); + ScheduledDirectTask task = new ScheduledDirectTask(decoratedRun, interruptibleWorker); Future f = ((ExecutorService)executor).submit(task); task.setFuture(f); return task; @@ -85,7 +87,7 @@ public Disposable scheduleDirect(@NonNull Runnable run, final long delay, final final Runnable decoratedRun = RxJavaPlugins.onSchedule(run); if (executor instanceof ScheduledExecutorService) { try { - ScheduledDirectTask task = new ScheduledDirectTask(decoratedRun); + ScheduledDirectTask task = new ScheduledDirectTask(decoratedRun, interruptibleWorker); Future f = ((ScheduledExecutorService)executor).schedule(task, delay, unit); task.setFuture(f); return task; @@ -97,7 +99,7 @@ public Disposable scheduleDirect(@NonNull Runnable run, final long delay, final final DelayedRunnable dr = new DelayedRunnable(decoratedRun); - Disposable delayed = HELPER.scheduleDirect(new DelayedDispose(dr), delay, unit); + Disposable delayed = SingleHolder.HELPER.scheduleDirect(new DelayedDispose(dr), delay, unit); dr.timed.replace(delayed); @@ -110,7 +112,7 @@ public Disposable schedulePeriodicallyDirect(@NonNull Runnable run, long initial if (executor instanceof ScheduledExecutorService) { Runnable decoratedRun = RxJavaPlugins.onSchedule(run); try { - ScheduledDirectPeriodicTask task = new ScheduledDirectPeriodicTask(decoratedRun); + ScheduledDirectPeriodicTask task = new ScheduledDirectPeriodicTask(decoratedRun, interruptibleWorker); Future f = ((ScheduledExecutorService)executor).scheduleAtFixedRate(task, initialDelay, period, unit); task.setFuture(f); return task; @@ -202,7 +204,7 @@ public Disposable schedule(@NonNull Runnable run, long delay, @NonNull TimeUnit final Runnable decoratedRun = RxJavaPlugins.onSchedule(run); - ScheduledRunnable sr = new ScheduledRunnable(new SequentialDispose(mar, decoratedRun), tasks); + ScheduledRunnable sr = new ScheduledRunnable(new SequentialDispose(mar, decoratedRun), tasks, interruptibleWorker); tasks.add(sr); if (executor instanceof ScheduledExecutorService) { @@ -215,7 +217,7 @@ public Disposable schedule(@NonNull Runnable run, long delay, @NonNull TimeUnit return EmptyDisposable.INSTANCE; } } else { - final Disposable d = HELPER.scheduleDirect(sr, delay, unit); + final Disposable d = SingleHolder.HELPER.scheduleDirect(sr, delay, unit); sr.setFuture(new DisposeOnCancel(d)); } @@ -257,9 +259,7 @@ void runFair() { } Runnable run = q.poll(); - if (run != null) { - run.run(); - } + run.run(); // never null because of offer + increment happens first if (disposed) { q.clear(); @@ -322,6 +322,10 @@ public void run() { } try { actual.run(); + } catch (Throwable ex) { + // Exceptions.throwIfFatal(ex); nowhere to go + RxJavaPlugins.onError(ex); + throw ex; } finally { lazySet(true); } @@ -388,7 +392,13 @@ public void run() { thread = Thread.currentThread(); if (compareAndSet(READY, RUNNING)) { try { - run.run(); + try { + run.run(); + } catch (Throwable ex) { + // Exceptions.throwIfFatal(ex); nowhere to go + RxJavaPlugins.onError(ex); + throw ex; + } } finally { thread = null; if (compareAndSet(RUNNING, FINISHED)) { @@ -465,11 +475,17 @@ public void run() { Runnable r = get(); if (r != null) { try { - r.run(); - } finally { - lazySet(null); - timed.lazySet(DisposableHelper.DISPOSED); - direct.lazySet(DisposableHelper.DISPOSED); + try { + r.run(); + } finally { + lazySet(null); + timed.lazySet(DisposableHelper.DISPOSED); + direct.lazySet(DisposableHelper.DISPOSED); + } + } catch (Throwable ex) { + // Exceptions.throwIfFatal(ex); nowhere to go + RxJavaPlugins.onError(ex); + throw ex; } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/ImmediateThinScheduler.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/ImmediateThinScheduler.java index 21fbbead832..e2430e74cbc 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/ImmediateThinScheduler.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/ImmediateThinScheduler.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/InstantPeriodicTask.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/InstantPeriodicTask.java index a855b44683c..1fd37f5d933 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/InstantPeriodicTask.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/InstantPeriodicTask.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.schedulers; @@ -20,7 +17,6 @@ import java.util.concurrent.atomic.AtomicReference; import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.plugins.RxJavaPlugins; @@ -54,12 +50,13 @@ public Void call() { runner = Thread.currentThread(); try { task.run(); - setRest(executor.submit(this)); runner = null; + setRest(executor.submit(this)); } catch (Throwable ex) { - Exceptions.throwIfFatal(ex); + // Exceptions.throwIfFatal(ex); nowhere to go runner = null; RxJavaPlugins.onError(ex); + throw ex; } return null; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/IoScheduler.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/IoScheduler.java index 3a4bac58b25..cfe95206856 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/IoScheduler.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/IoScheduler.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.schedulers; @@ -48,6 +45,10 @@ public final class IoScheduler extends Scheduler { /** The name of the system property for setting the thread priority for this Scheduler. */ private static final String KEY_IO_PRIORITY = "rx3.io-priority"; + /** The name of the system property for setting the release behaviour for this Scheduler. */ + private static final String KEY_SCHEDULED_RELEASE = "rx3.io-scheduled-release"; + static boolean USE_SCHEDULED_RELEASE; + static final CachedWorkerPool NONE; static { @@ -63,6 +64,8 @@ public final class IoScheduler extends Scheduler { EVICTOR_THREAD_FACTORY = new RxThreadFactory(EVICTOR_THREAD_NAME_PREFIX, priority); + USE_SCHEDULED_RELEASE = Boolean.getBoolean(KEY_SCHEDULED_RELEASE); + NONE = new CachedWorkerPool(0, null, WORKER_THREAD_FACTORY); NONE.shutdown(); } @@ -93,7 +96,7 @@ static final class CachedWorkerPool implements Runnable { @Override public void run() { - evictExpiredWorkers(); + evictExpiredWorkers(expiringWorkerQueue, allWorkers); } ThreadWorker get() { @@ -120,7 +123,7 @@ void release(ThreadWorker threadWorker) { expiringWorkerQueue.offer(threadWorker); } - void evictExpiredWorkers() { + static void evictExpiredWorkers(ConcurrentLinkedQueue expiringWorkerQueue, CompositeDisposable allWorkers) { if (!expiringWorkerQueue.isEmpty()) { long currentTimestamp = now(); @@ -138,7 +141,7 @@ void evictExpiredWorkers() { } } - long now() { + static long now() { return System.nanoTime(); } @@ -178,15 +181,9 @@ public void start() { @Override public void shutdown() { - for (;;) { - CachedWorkerPool curr = pool.get(); - if (curr == NONE) { - return; - } - if (pool.compareAndSet(curr, NONE)) { - curr.shutdown(); - return; - } + CachedWorkerPool curr = pool.getAndSet(NONE); + if (curr != NONE) { + curr.shutdown(); } } @@ -200,7 +197,7 @@ public int size() { return pool.get().allWorkers.size(); } - static final class EventLoopWorker extends Scheduler.Worker { + static final class EventLoopWorker extends Scheduler.Worker implements Runnable { private final CompositeDisposable tasks; private final CachedWorkerPool pool; private final ThreadWorker threadWorker; @@ -218,11 +215,20 @@ public void dispose() { if (once.compareAndSet(false, true)) { tasks.dispose(); - // releasing the pool should be the last action - pool.release(threadWorker); + if (USE_SCHEDULED_RELEASE) { + threadWorker.scheduleActual(this, 0, TimeUnit.NANOSECONDS, null); + } else { + // releasing the pool should be the last action + pool.release(threadWorker); + } } } + @Override + public void run() { + pool.release(threadWorker); + } + @Override public boolean isDisposed() { return once.get(); @@ -241,7 +247,8 @@ public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull Ti } static final class ThreadWorker extends NewThreadWorker { - private long expirationTime; + + long expirationTime; ThreadWorker(ThreadFactory threadFactory) { super(threadFactory); diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/NewThreadScheduler.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/NewThreadScheduler.java index 1cd48ce1e04..1c29efddc54 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/NewThreadScheduler.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/NewThreadScheduler.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.schedulers; diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/NewThreadWorker.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/NewThreadWorker.java index d811c8e7823..764241e76e3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/NewThreadWorker.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/NewThreadWorker.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,7 @@ * worker but doesn't perform task-tracking operations. * */ -public class NewThreadWorker extends Scheduler.Worker implements Disposable { +public class NewThreadWorker extends Scheduler.Worker { private final ScheduledExecutorService executor; volatile boolean disposed; @@ -59,7 +59,7 @@ public Disposable schedule(@NonNull final Runnable action, long delayTime, @NonN * @return the ScheduledRunnable instance */ public Disposable scheduleDirect(final Runnable run, long delayTime, TimeUnit unit) { - ScheduledDirectTask task = new ScheduledDirectTask(RxJavaPlugins.onSchedule(run)); + ScheduledDirectTask task = new ScheduledDirectTask(RxJavaPlugins.onSchedule(run), true); try { Future f; if (delayTime <= 0L) { @@ -104,7 +104,7 @@ public Disposable schedulePeriodicallyDirect(Runnable run, long initialDelay, lo return periodicWrapper; } - ScheduledDirectPeriodicTask task = new ScheduledDirectPeriodicTask(decoratedRun); + ScheduledDirectPeriodicTask task = new ScheduledDirectPeriodicTask(decoratedRun, true); try { Future f = executor.scheduleAtFixedRate(task, initialDelay, period, unit); task.setFuture(f); @@ -116,10 +116,8 @@ public Disposable schedulePeriodicallyDirect(Runnable run, long initialDelay, lo } /** - * Wraps the given runnable into a ScheduledRunnable and schedules it + * Wraps and returns the given runnable into a ScheduledRunnable and schedules it * on the underlying ScheduledExecutorService. - *

If the schedule has been rejected, the ScheduledRunnable.wasScheduled will return - * false. * @param run the runnable instance * @param delayTime the time to delay the execution * @param unit the time unit diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/NonBlockingThread.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/NonBlockingThread.java index f800f1ac4e8..ff6dd5c7063 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/NonBlockingThread.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/NonBlockingThread.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/RxThreadFactory.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/RxThreadFactory.java index 5bd0614b894..9b3a7968c3e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/RxThreadFactory.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/RxThreadFactory.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/ScheduledDirectPeriodicTask.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/ScheduledDirectPeriodicTask.java index ac30532e687..1862035dde4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/ScheduledDirectPeriodicTask.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/ScheduledDirectPeriodicTask.java @@ -1,22 +1,18 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.schedulers; -import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** @@ -28,8 +24,8 @@ public final class ScheduledDirectPeriodicTask extends AbstractDirectTask implem private static final long serialVersionUID = 1811839108042568751L; - public ScheduledDirectPeriodicTask(Runnable runnable) { - super(runnable); + public ScheduledDirectPeriodicTask(Runnable runnable, boolean interruptOnCancel) { + super(runnable, interruptOnCancel); } @Override @@ -39,10 +35,11 @@ public void run() { runnable.run(); runner = null; } catch (Throwable ex) { - Exceptions.throwIfFatal(ex); + // Exceptions.throwIfFatal(ex); nowhere to go + dispose(); runner = null; - lazySet(FINISHED); RxJavaPlugins.onError(ex); + throw ex; } } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/ScheduledDirectTask.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/ScheduledDirectTask.java index d48ccf8ab61..6ca89929710 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/ScheduledDirectTask.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/ScheduledDirectTask.java @@ -1,23 +1,22 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.schedulers; import java.util.concurrent.Callable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + /** * A Callable to be submitted to an ExecutorService that runs a Runnable * action and manages completion/cancellation. @@ -27,18 +26,24 @@ public final class ScheduledDirectTask extends AbstractDirectTask implements Cal private static final long serialVersionUID = 1811839108042568751L; - public ScheduledDirectTask(Runnable runnable) { - super(runnable); + public ScheduledDirectTask(Runnable runnable, boolean interruptOnCancel) { + super(runnable, interruptOnCancel); } @Override public Void call() { runner = Thread.currentThread(); try { - runnable.run(); - } finally { - lazySet(FINISHED); - runner = null; + try { + runnable.run(); + } finally { + lazySet(FINISHED); + runner = null; + } + } catch (Throwable ex) { + // Exceptions.throwIfFatal(e); nowhere to go + RxJavaPlugins.onError(ex); + throw ex; } return null; } diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/ScheduledRunnable.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/ScheduledRunnable.java index 45072a2abdc..2a1baa641a2 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/ScheduledRunnable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/ScheduledRunnable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,6 +24,7 @@ public final class ScheduledRunnable extends AtomicReferenceArray private static final long serialVersionUID = -6120223772001106981L; final Runnable actual; + final boolean interruptOnCancel; /** Indicates that the parent tracking this task has been notified about its completion. */ static final Object PARENT_DISPOSED = new Object(); @@ -41,12 +42,26 @@ public final class ScheduledRunnable extends AtomicReferenceArray /** * Creates a ScheduledRunnable by wrapping the given action and setting * up the optional parent. + * The underlying future will be interrupted if the task is disposed asynchronously. * @param actual the runnable to wrap, not-null (not verified) * @param parent the parent tracking container or null if none */ public ScheduledRunnable(Runnable actual, DisposableContainer parent) { + this(actual, parent, true); + } + + /** + * Creates a ScheduledRunnable by wrapping the given action and setting + * up the optional parent. + * @param actual the runnable to wrap, not-null (not verified) + * @param parent the parent tracking container or null if none + * @param interruptOnCancel if true, the underlying future will be interrupted when disposing + * this task from a different thread than it is running on. + */ + public ScheduledRunnable(Runnable actual, DisposableContainer parent, boolean interruptOnCancel) { super(3); this.actual = actual; + this.interruptOnCancel = interruptOnCancel; this.lazySet(0, parent); } @@ -66,9 +81,9 @@ public void run() { } catch (Throwable e) { // Exceptions.throwIfFatal(e); nowhere to go RxJavaPlugins.onError(e); + throw e; } } finally { - lazySet(THREAD_INDEX, null); Object o = get(PARENT_INDEX); if (o != PARENT_DISPOSED && compareAndSet(PARENT_INDEX, o, DONE) && o != null) { ((DisposableContainer)o).delete(this); @@ -80,6 +95,7 @@ public void run() { break; } } + lazySet(THREAD_INDEX, null); } } @@ -94,7 +110,7 @@ public void setFuture(Future f) { return; } if (o == ASYNC_DISPOSED) { - f.cancel(true); + f.cancel(interruptOnCancel); return; } if (compareAndSet(FUTURE_INDEX, o, f)) { @@ -113,7 +129,7 @@ public void dispose() { boolean async = get(THREAD_INDEX) != Thread.currentThread(); if (compareAndSet(FUTURE_INDEX, o, async ? ASYNC_DISPOSED : SYNC_DISPOSED)) { if (o != null) { - ((Future)o).cancel(async); + ((Future)o).cancel(async && interruptOnCancel); } break; } @@ -136,4 +152,26 @@ public boolean isDisposed() { Object o = get(PARENT_INDEX); return o == PARENT_DISPOSED || o == DONE; } + + @Override + public String toString() { + String state; + Object o = get(FUTURE_INDEX); + if (o == DONE) { + state = "Finished"; + } else if (o == SYNC_DISPOSED) { + state = "Disposed(Sync)"; + } else if (o == ASYNC_DISPOSED) { + state = "Disposed(Async)"; + } else { + o = get(THREAD_INDEX); + if (o == null) { + state = "Waiting"; + } else { + state = "Running on " + o; + } + } + + return getClass().getSimpleName() + "[" + state + "]"; + } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/SchedulerMultiWorkerSupport.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/SchedulerMultiWorkerSupport.java index d42fa32cfb7..b1e186adc91 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/SchedulerMultiWorkerSupport.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/SchedulerMultiWorkerSupport.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/SchedulerPoolFactory.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/SchedulerPoolFactory.java index 333d4ded9e1..44a824a168d 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/SchedulerPoolFactory.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/SchedulerPoolFactory.java @@ -1,24 +1,19 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.schedulers; -import java.util.*; import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicReference; import io.reactivex.rxjava3.exceptions.Exceptions; import io.reactivex.rxjava3.functions.Function; @@ -34,86 +29,11 @@ private SchedulerPoolFactory() { static final String PURGE_ENABLED_KEY = "rx3.purge-enabled"; - /** - * Indicates the periodic purging of the ScheduledExecutorService is enabled. - */ public static final boolean PURGE_ENABLED; - static final String PURGE_PERIOD_SECONDS_KEY = "rx3.purge-period-seconds"; - - /** - * Indicates the purge period of the ScheduledExecutorServices created by create(). - */ - public static final int PURGE_PERIOD_SECONDS; - - static final AtomicReference PURGE_THREAD = - new AtomicReference<>(); - - // Upcast to the Map interface here to avoid 8.x compatibility issues. - // See http://stackoverflow.com/a/32955708/61158 - static final Map POOLS = - new ConcurrentHashMap<>(); - - /** - * Starts the purge thread if not already started. - */ - public static void start() { - tryStart(PURGE_ENABLED); - } - - static void tryStart(boolean purgeEnabled) { - if (purgeEnabled) { - for (;;) { - ScheduledExecutorService curr = PURGE_THREAD.get(); - if (curr != null) { - return; - } - ScheduledExecutorService next = Executors.newScheduledThreadPool(1, new RxThreadFactory("RxSchedulerPurge")); - if (PURGE_THREAD.compareAndSet(curr, next)) { - - next.scheduleAtFixedRate(new ScheduledTask(), PURGE_PERIOD_SECONDS, PURGE_PERIOD_SECONDS, TimeUnit.SECONDS); - - return; - } else { - next.shutdownNow(); - } - } - } - } - - /** - * Stops the purge thread. - */ - public static void shutdown() { - ScheduledExecutorService exec = PURGE_THREAD.getAndSet(null); - if (exec != null) { - exec.shutdownNow(); - } - POOLS.clear(); - } - static { SystemPropertyAccessor propertyAccessor = new SystemPropertyAccessor(); PURGE_ENABLED = getBooleanProperty(true, PURGE_ENABLED_KEY, true, true, propertyAccessor); - PURGE_PERIOD_SECONDS = getIntProperty(PURGE_ENABLED, PURGE_PERIOD_SECONDS_KEY, 1, 1, propertyAccessor); - - start(); - } - - static int getIntProperty(boolean enabled, String key, int defaultNotFound, int defaultNotEnabled, Function propertyAccessor) { - if (enabled) { - try { - String value = propertyAccessor.apply(key); - if (value == null) { - return defaultNotFound; - } - return Integer.parseInt(value); - } catch (Throwable ex) { - Exceptions.throwIfFatal(ex); - return defaultNotFound; - } - } - return defaultNotEnabled; } static boolean getBooleanProperty(boolean enabled, String key, boolean defaultNotFound, boolean defaultNotEnabled, Function propertyAccessor) { @@ -145,28 +65,8 @@ public String apply(String t) { * @return the ScheduledExecutorService */ public static ScheduledExecutorService create(ThreadFactory factory) { - final ScheduledExecutorService exec = Executors.newScheduledThreadPool(1, factory); - tryPutIntoPool(PURGE_ENABLED, exec); + final ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1, factory); + exec.setRemoveOnCancelPolicy(PURGE_ENABLED); return exec; } - - static void tryPutIntoPool(boolean purgeEnabled, ScheduledExecutorService exec) { - if (purgeEnabled && exec instanceof ScheduledThreadPoolExecutor) { - ScheduledThreadPoolExecutor e = (ScheduledThreadPoolExecutor) exec; - POOLS.put(e, exec); - } - } - - static final class ScheduledTask implements Runnable { - @Override - public void run() { - for (ScheduledThreadPoolExecutor e : new ArrayList<>(POOLS.keySet())) { - if (e.isShutdown()) { - POOLS.remove(e); - } else { - e.purge(); - } - } - } - } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/SchedulerWhen.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/SchedulerWhen.java index ddff75388b9..814c971f1c6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/SchedulerWhen.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/SchedulerWhen.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.schedulers; import java.util.concurrent.TimeUnit; @@ -53,11 +51,13 @@ * thread pool: * *
+ * {@code
  * Scheduler limitScheduler = Schedulers.computation().when(workers -> {
  *  // use merge max concurrent to limit the number of concurrent
  *  // callbacks two at a time
  *  return Completable.merge(Observable.merge(workers), 2);
  * });
+ * }
  * 
*

* This is a slightly different way to limit the concurrency but it has some @@ -71,19 +71,22 @@ * to the second. * *

+ * {@code
  * Scheduler limitScheduler = Schedulers.computation().when(workers -> {
  *  // use merge max concurrent to limit the number of concurrent
  *  // Observables two at a time
  *  return Completable.merge(Observable.merge(workers, 2));
  * });
+ * }
  * 
* - * Slowing down the rate to no more than than 1 a second. This suffers from the + * Slowing down the rate to no more than 1 a second. This suffers from the * same problem as the one above I could find an {@link Observable} operator * that limits the rate without dropping the values (aka leaky bucket * algorithm). * *
+ * {@code
  * Scheduler slowScheduler = Schedulers.computation().when(workers -> {
  *  // use concatenate to make each worker happen one at a time.
  *  return Completable.concat(workers.map(actions -> {
@@ -91,6 +94,7 @@
  *      return Completable.merge(actions.delaySubscription(1, TimeUnit.SECONDS));
  *  }));
  * });
+ * }
  * 
*

History 2.0.1 - experimental * @since 2.1 @@ -187,21 +191,7 @@ public boolean isDisposed() { @Override public void dispose() { - Disposable oldState; - // no matter what the current state is the new state is going to be - Disposable newState = DISPOSED; - do { - oldState = get(); - if (oldState == DISPOSED) { - // the action has already been unsubscribed - return; - } - } while (!compareAndSet(oldState, newState)); - - if (oldState != SUBSCRIBED) { - // the action was scheduled. stop it. - oldState.dispose(); - } + getAndSet(DISPOSED).dispose(); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/SingleScheduler.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/SingleScheduler.java index 13c7430f942..98d3b04626a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/SingleScheduler.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/SingleScheduler.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.schedulers; import java.util.concurrent.*; @@ -90,12 +91,9 @@ public void start() { @Override public void shutdown() { - ScheduledExecutorService current = executor.get(); + ScheduledExecutorService current = executor.getAndSet(SHUTDOWN); if (current != SHUTDOWN) { - current = executor.getAndSet(SHUTDOWN); - if (current != SHUTDOWN) { - current.shutdownNow(); - } + current.shutdownNow(); } } @@ -108,7 +106,7 @@ public Worker createWorker() { @NonNull @Override public Disposable scheduleDirect(@NonNull Runnable run, long delay, TimeUnit unit) { - ScheduledDirectTask task = new ScheduledDirectTask(RxJavaPlugins.onSchedule(run)); + ScheduledDirectTask task = new ScheduledDirectTask(RxJavaPlugins.onSchedule(run), true); try { Future f; if (delay <= 0L) { @@ -148,7 +146,7 @@ public Disposable schedulePeriodicallyDirect(@NonNull Runnable run, long initial return periodicWrapper; } - ScheduledDirectPeriodicTask task = new ScheduledDirectPeriodicTask(decoratedRun); + ScheduledDirectPeriodicTask task = new ScheduledDirectPeriodicTask(decoratedRun, true); try { Future f = executor.get().scheduleAtFixedRate(task, initialDelay, period, unit); task.setFuture(f); diff --git a/src/main/java/io/reactivex/rxjava3/internal/schedulers/TrampolineScheduler.java b/src/main/java/io/reactivex/rxjava3/internal/schedulers/TrampolineScheduler.java index 5ddd8677837..04496482b06 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/schedulers/TrampolineScheduler.java +++ b/src/main/java/io/reactivex/rxjava3/internal/schedulers/TrampolineScheduler.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.schedulers; @@ -65,7 +62,7 @@ public Disposable scheduleDirect(@NonNull Runnable run, long delay, TimeUnit uni return EmptyDisposable.INSTANCE; } - static final class TrampolineWorker extends Scheduler.Worker implements Disposable { + static final class TrampolineWorker extends Scheduler.Worker { final PriorityBlockingQueue queue = new PriorityBlockingQueue<>(); private final AtomicInteger wip = new AtomicInteger(); diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableConditionalSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableConditionalSubscriber.java index ae1e72c3f85..645a3171f2b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableConditionalSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableConditionalSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,8 +16,9 @@ import org.reactivestreams.Subscription; import io.reactivex.rxjava3.exceptions.Exceptions; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableSubscriber.java index b0944cacec3..162a9dbe552 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,8 +17,8 @@ import io.reactivex.rxjava3.core.FlowableSubscriber; import io.reactivex.rxjava3.exceptions.Exceptions; -import io.reactivex.rxjava3.internal.fuseable.QueueSubscription; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingBaseSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingBaseSubscriber.java index cf93064c6a0..68fa0df3eb0 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingBaseSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingBaseSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.subscribers; import java.util.concurrent.CountDownLatch; diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingFirstSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingFirstSubscriber.java index 228023b3d9e..1226eca8451 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingFirstSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingFirstSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingLastSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingLastSubscriber.java index 18891937707..05be9d79fa3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingLastSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingLastSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingSubscriber.java index 9ddba51e3c8..4617833fc48 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BlockingSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BoundedSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BoundedSubscriber.java index 7ea697a3aba..a55f4ae4fae 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/BoundedSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/BoundedSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -136,4 +136,4 @@ public void cancel() { public boolean hasCustomOnError() { return onError != Functions.ON_ERROR_MISSING; } -} \ No newline at end of file +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/DeferredScalarSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/DeferredScalarSubscriber.java index 5fca99286af..11123962f27 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/DeferredScalarSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/DeferredScalarSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/DisposableAutoReleaseSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/DisposableAutoReleaseSubscriber.java new file mode 100644 index 00000000000..3b9d2d99b3d --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/DisposableAutoReleaseSubscriber.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +/* + * Copyright 2016-2019 David Karnok + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.reactivex.rxjava3.internal.subscribers; + +import java.util.concurrent.atomic.AtomicReference; + +import org.reactivestreams.Subscription; + +import io.reactivex.rxjava3.core.FlowableSubscriber; +import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.observers.LambdaConsumerIntrospection; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + +/** + * Wraps lambda callbacks and when the upstream terminates or this subscriber gets disposed, + * removes itself from a {@link io.reactivex.rxjava3.disposables.CompositeDisposable}. + *

History: 0.18.0 @ RxJavaExtensions + * @param the element type consumed + * @since 3.1.0 + */ +public final class DisposableAutoReleaseSubscriber +extends AtomicReference +implements FlowableSubscriber, Disposable, LambdaConsumerIntrospection { + + private static final long serialVersionUID = 8924480688481408726L; + + final AtomicReference composite; + + final Consumer onNext; + + final Consumer onError; + + final Action onComplete; + + public DisposableAutoReleaseSubscriber( + DisposableContainer composite, + Consumer onNext, + Consumer onError, + Action onComplete + ) { + this.onNext = onNext; + this.onError = onError; + this.onComplete = onComplete; + this.composite = new AtomicReference<>(composite); + } + + @Override + public void onNext(T t) { + if (get() != SubscriptionHelper.CANCELLED) { + try { + onNext.accept(t); + } catch (Throwable e) { + Exceptions.throwIfFatal(e); + get().cancel(); + onError(e); + } + } + } + + @Override + public void onError(Throwable t) { + if (get() != SubscriptionHelper.CANCELLED) { + lazySet(SubscriptionHelper.CANCELLED); + try { + onError.accept(t); + } catch (Throwable e) { + Exceptions.throwIfFatal(e); + RxJavaPlugins.onError(new CompositeException(t, e)); + } + } else { + RxJavaPlugins.onError(t); + } + removeSelf(); + } + + @Override + public void onComplete() { + if (get() != SubscriptionHelper.CANCELLED) { + lazySet(SubscriptionHelper.CANCELLED); + try { + onComplete.run(); + } catch (Throwable e) { + Exceptions.throwIfFatal(e); + RxJavaPlugins.onError(e); + } + } + removeSelf(); + } + + @Override + public void dispose() { + SubscriptionHelper.cancel(this); + removeSelf(); + } + + void removeSelf() { + DisposableContainer c = composite.getAndSet(null); + if (c != null) { + c.delete(this); + } + } + + @Override + public boolean isDisposed() { + return SubscriptionHelper.CANCELLED == get(); + } + + @Override + public void onSubscribe(Subscription s) { + if (SubscriptionHelper.setOnce(this, s)) { + s.request(Long.MAX_VALUE); + } + } + + @Override + public boolean hasCustomOnError() { + return onError != Functions.ON_ERROR_MISSING; + } + +} diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/ForEachWhileSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/ForEachWhileSubscriber.java index 34d00eef9d7..cb5ff01a13c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/ForEachWhileSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/ForEachWhileSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/FutureSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/FutureSubscriber.java index 59edd4f80d4..145195e2cc4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/FutureSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/FutureSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,9 +19,9 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; -import io.reactivex.rxjava3.annotations.NonNull; import org.reactivestreams.Subscription; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.FlowableSubscriber; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.BlockingHelper; @@ -128,18 +128,16 @@ public void onNext(T t) { @Override public void onError(Throwable t) { - for (;;) { + if (error == null) { Subscription a = upstream.get(); - if (a == this || a == SubscriptionHelper.CANCELLED) { - RxJavaPlugins.onError(t); - return; - } - error = t; - if (upstream.compareAndSet(a, this)) { + if (a != this && a != SubscriptionHelper.CANCELLED + && upstream.compareAndSet(a, this)) { + error = t; countDown(); return; } } + RxJavaPlugins.onError(t); } @Override @@ -148,15 +146,12 @@ public void onComplete() { onError(new NoSuchElementException("The source is empty")); return; } - for (;;) { - Subscription a = upstream.get(); - if (a == this || a == SubscriptionHelper.CANCELLED) { - return; - } - if (upstream.compareAndSet(a, this)) { - countDown(); - return; - } + Subscription a = upstream.get(); + if (a == this || a == SubscriptionHelper.CANCELLED) { + return; + } + if (upstream.compareAndSet(a, this)) { + countDown(); } } diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/InnerQueuedSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/InnerQueuedSubscriber.java index c53138e3d72..f946ec7deb5 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/InnerQueuedSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/InnerQueuedSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,9 +18,10 @@ import org.reactivestreams.Subscription; import io.reactivex.rxjava3.core.FlowableSubscriber; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.QueueDrainHelper; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; /** * Subscriber that can fuse with the upstream and calls a support interface @@ -115,18 +116,6 @@ public void request(long n) { } } - public void requestOne() { - if (fusionMode != QueueSubscription.SYNC) { - long p = produced + 1; - if (p == limit) { - produced = 0L; - get().request(p); - } else { - produced = p; - } - } - } - @Override public void cancel() { SubscriptionHelper.cancel(this); diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/InnerQueuedSubscriberSupport.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/InnerQueuedSubscriberSupport.java index e7deb5c4115..3844c5b981a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/InnerQueuedSubscriberSupport.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/InnerQueuedSubscriberSupport.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/LambdaSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/LambdaSubscriber.java index daa76fdfbf5..f137237e975 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/LambdaSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/LambdaSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/QueueDrainSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/QueueDrainSubscriber.java index c66505a0711..8fb7f552953 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/QueueDrainSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/QueueDrainSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,9 +20,9 @@ import io.reactivex.rxjava3.core.FlowableSubscriber; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.MissingBackpressureException; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.SimplePlainQueue; /** * Abstract base class for subscribers that hold another subscriber, a queue @@ -84,7 +84,7 @@ protected final void fastPathEmitMax(U value, boolean delayError, Disposable dis } } else { dispose.dispose(); - s.onError(new MissingBackpressureException("Could not emit buffer due to lack of requests")); + s.onError(MissingBackpressureException.createDefault()); return; } } else { @@ -118,7 +118,7 @@ protected final void fastPathOrderedEmitMax(U value, boolean delayError, Disposa } else { cancelled = true; dispose.dispose(); - s.onError(new MissingBackpressureException("Could not emit buffer due to lack of requests")); + s.onError(MissingBackpressureException.createDefault()); return; } } else { diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/SinglePostCompleteSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/SinglePostCompleteSubscriber.java index ab9f9ba7999..ceec9f6b90a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/SinglePostCompleteSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/SinglePostCompleteSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/StrictSubscriber.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/StrictSubscriber.java index f3511260444..265acd60a57 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/StrictSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/StrictSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscribers/SubscriberResourceWrapper.java b/src/main/java/io/reactivex/rxjava3/internal/subscribers/SubscriberResourceWrapper.java index 4c9b6b49306..df85e953247 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscribers/SubscriberResourceWrapper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscribers/SubscriberResourceWrapper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/ArrayCompositeSubscription.java b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/ArrayCompositeSubscription.java index 628891a7e6f..ce4b2b5ac82 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/ArrayCompositeSubscription.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/ArrayCompositeSubscription.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/AsyncSubscription.java b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/AsyncSubscription.java index 62973e7440c..d33d05c8d1b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/AsyncSubscription.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/AsyncSubscription.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/BasicIntQueueSubscription.java b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/BasicIntQueueSubscription.java index 862fb51b4b7..46b420354b8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/BasicIntQueueSubscription.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/BasicIntQueueSubscription.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,14 +15,15 @@ import java.util.concurrent.atomic.AtomicInteger; -import io.reactivex.rxjava3.internal.fuseable.QueueSubscription; +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.operators.QueueSubscription; /** * Base class extending AtomicInteger (wip or request accounting) and QueueSubscription (fusion). * * @param the value type */ -public abstract class BasicIntQueueSubscription extends AtomicInteger implements QueueSubscription { +public abstract class BasicIntQueueSubscription<@NonNull T> extends AtomicInteger implements QueueSubscription { private static final long serialVersionUID = -6671519529404341862L; diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/BasicQueueSubscription.java b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/BasicQueueSubscription.java index 54d33f26cb8..684bdf4e80f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/BasicQueueSubscription.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/BasicQueueSubscription.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,7 +15,7 @@ import java.util.concurrent.atomic.AtomicLong; -import io.reactivex.rxjava3.internal.fuseable.QueueSubscription; +import io.reactivex.rxjava3.operators.QueueSubscription; /** * Base class extending AtomicLong (wip or request accounting) and QueueSubscription (fusion). diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/BooleanSubscription.java b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/BooleanSubscription.java index 117b09b60ce..2d7f01ef057 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/BooleanSubscription.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/BooleanSubscription.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.subscriptions; import java.util.concurrent.atomic.AtomicBoolean; diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscription.java b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscription.java index b50b4e13f9c..544fac8b58a 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscription.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscription.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,7 +15,7 @@ import org.reactivestreams.Subscriber; -import io.reactivex.rxjava3.annotations.Nullable; +import io.reactivex.rxjava3.annotations.*; /** * A subscription that signals a single value eventually. @@ -33,7 +33,7 @@ * Where exclusively set means any other bits are 0 when that bit is set. * @param the value type */ -public class DeferredScalarSubscription extends BasicIntQueueSubscription { +public class DeferredScalarSubscription<@NonNull T> extends BasicIntQueueSubscription { private static final long serialVersionUID = -2151279923272604993L; @@ -115,7 +115,7 @@ public final void complete(T v) { lazySet(FUSED_READY); Subscriber a = downstream; - a.onNext(v); + a.onNext(null); if (get() != CANCELLED) { a.onComplete(); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/EmptySubscription.java b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/EmptySubscription.java index 2da5f529a12..6b2c033d5ec 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/EmptySubscription.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/EmptySubscription.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,7 +16,7 @@ import org.reactivestreams.Subscriber; import io.reactivex.rxjava3.annotations.Nullable; -import io.reactivex.rxjava3.internal.fuseable.QueueSubscription; +import io.reactivex.rxjava3.operators.QueueSubscription; /** * An empty subscription that does nothing other than validates the request amount. diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/ScalarSubscription.java b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/ScalarSubscription.java index e854c11f921..ef1e35e7530 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/ScalarSubscription.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/ScalarSubscription.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,7 +18,7 @@ import org.reactivestreams.Subscriber; import io.reactivex.rxjava3.annotations.Nullable; -import io.reactivex.rxjava3.internal.fuseable.QueueSubscription; +import io.reactivex.rxjava3.operators.QueueSubscription; /** * A Subscription that holds a constant value and emits it only when requested. diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionArbiter.java b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionArbiter.java index 44c5fe5845f..7d964224ebb 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionArbiter.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionArbiter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -12,18 +12,6 @@ */ package io.reactivex.rxjava3.internal.subscriptions; -/** - * Copyright (c) 2016-present, RxJava Contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See - * the License for the specific language governing permissions and limitations under the License. - */ import java.util.Objects; import java.util.concurrent.atomic.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionHelper.java b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionHelper.java index 8cfc3f5a7c7..922ac9c3c9c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionHelper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/AppendOnlyLinkedArrayList.java b/src/main/java/io/reactivex/rxjava3/internal/util/AppendOnlyLinkedArrayList.java index a2a78e7b7e7..3c17b880096 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/AppendOnlyLinkedArrayList.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/AppendOnlyLinkedArrayList.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/ArrayListSupplier.java b/src/main/java/io/reactivex/rxjava3/internal/util/ArrayListSupplier.java index 7338c990404..6379cfcab84 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/ArrayListSupplier.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/ArrayListSupplier.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/AtomicThrowable.java b/src/main/java/io/reactivex/rxjava3/internal/util/AtomicThrowable.java index 222008e216a..3ef92cb77a3 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/AtomicThrowable.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/AtomicThrowable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/BackpressureHelper.java b/src/main/java/io/reactivex/rxjava3/internal/util/BackpressureHelper.java index 4ccfe678454..73b15382c89 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/BackpressureHelper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/BackpressureHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.util; import java.util.concurrent.atomic.AtomicLong; diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/BlockingHelper.java b/src/main/java/io/reactivex/rxjava3/internal/util/BlockingHelper.java index 57d9f863b31..84acadee6fb 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/BlockingHelper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/BlockingHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/BlockingIgnoringReceiver.java b/src/main/java/io/reactivex/rxjava3/internal/util/BlockingIgnoringReceiver.java index f0d90e4708a..8d4c1fb76e4 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/BlockingIgnoringReceiver.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/BlockingIgnoringReceiver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/ConnectConsumer.java b/src/main/java/io/reactivex/rxjava3/internal/util/ConnectConsumer.java index 63fd12dc991..5d5246719db 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/ConnectConsumer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/ConnectConsumer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/EmptyComponent.java b/src/main/java/io/reactivex/rxjava3/internal/util/EmptyComponent.java index 1ffc9c51d4c..47390f57cb6 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/EmptyComponent.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/EmptyComponent.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/EndConsumerHelper.java b/src/main/java/io/reactivex/rxjava3/internal/util/EndConsumerHelper.java index 01b95a0a113..0e72353800f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/EndConsumerHelper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/EndConsumerHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/ErrorMode.java b/src/main/java/io/reactivex/rxjava3/internal/util/ErrorMode.java index e3ff3d5fdb7..02389f0b7a8 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/ErrorMode.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/ErrorMode.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/ExceptionHelper.java b/src/main/java/io/reactivex/rxjava3/internal/util/ExceptionHelper.java index 8b9d62317a4..1ddbb8aca11 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/ExceptionHelper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/ExceptionHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/HalfSerializer.java b/src/main/java/io/reactivex/rxjava3/internal/util/HalfSerializer.java index 54f787f55ab..e1bf5596e2c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/HalfSerializer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/HalfSerializer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.util; import java.util.concurrent.atomic.AtomicInteger; @@ -37,15 +38,18 @@ private HalfSerializer() { * @param value the value to emit * @param wip the serialization work-in-progress counter/indicator * @param errors the holder of Throwables + * @return true if the operation succeeded, false if there sequence completed */ - public static void onNext(Subscriber subscriber, T value, + public static boolean onNext(Subscriber subscriber, T value, AtomicInteger wip, AtomicThrowable errors) { if (wip.get() == 0 && wip.compareAndSet(0, 1)) { subscriber.onNext(value); - if (wip.decrementAndGet() != 0) { - errors.tryTerminateConsumer(subscriber); + if (wip.decrementAndGet() == 0) { + return true; } + errors.tryTerminateConsumer(subscriber); } + return false; } /** diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/HashMapSupplier.java b/src/main/java/io/reactivex/rxjava3/internal/util/HashMapSupplier.java index 46236ff2938..15c2884266e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/HashMapSupplier.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/HashMapSupplier.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/LinkedArrayList.java b/src/main/java/io/reactivex/rxjava3/internal/util/LinkedArrayList.java index 08d675a4afb..92ff9d30a6e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/LinkedArrayList.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/LinkedArrayList.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.util; import java.util.*; diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/ListAddBiConsumer.java b/src/main/java/io/reactivex/rxjava3/internal/util/ListAddBiConsumer.java index cd6c8e97509..fb643fcff30 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/ListAddBiConsumer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/ListAddBiConsumer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/MergerBiFunction.java b/src/main/java/io/reactivex/rxjava3/internal/util/MergerBiFunction.java index 64d9faff715..a736309019e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/MergerBiFunction.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/MergerBiFunction.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/NotificationLite.java b/src/main/java/io/reactivex/rxjava3/internal/util/NotificationLite.java index c37aa71da24..c27486d9cfd 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/NotificationLite.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/NotificationLite.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.util; import java.io.Serializable; diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/ObservableQueueDrain.java b/src/main/java/io/reactivex/rxjava3/internal/util/ObservableQueueDrain.java index c0187e9cc22..6d69b375d4b 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/ObservableQueueDrain.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/ObservableQueueDrain.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/OpenHashSet.java b/src/main/java/io/reactivex/rxjava3/internal/util/OpenHashSet.java index c5bf3bb6766..9967ca831d9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/OpenHashSet.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/OpenHashSet.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/Pow2.java b/src/main/java/io/reactivex/rxjava3/internal/util/Pow2.java index dd6df01d9e2..fd30ee04fb9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/Pow2.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/Pow2.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,6 +15,7 @@ * Original License: https://github.com/JCTools/JCTools/blob/master/LICENSE * Original location: https://github.com/JCTools/JCTools/blob/master/jctools-core/src/main/java/org/jctools/util/Pow2.java */ + package io.reactivex.rxjava3.internal.util; public final class Pow2 { diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/QueueDrain.java b/src/main/java/io/reactivex/rxjava3/internal/util/QueueDrain.java index 4a84e5e6ed5..481cbe0012e 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/QueueDrain.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/QueueDrain.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/QueueDrainHelper.java b/src/main/java/io/reactivex/rxjava3/internal/util/QueueDrainHelper.java index 9808e2fe0d6..fa0c500892f 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/QueueDrainHelper.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/QueueDrainHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.util; import java.util.Queue; @@ -21,8 +22,7 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.BooleanSupplier; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.*; +import io.reactivex.rxjava3.operators.*; /** * Utility class to help with the queue-drain serialization idiom. @@ -78,7 +78,7 @@ public static void drainMaxLoop(SimplePlainQueue q, Subscriber the value type * @param n the current request amount * @param actual the target Subscriber to send events to * @param queue the queue to drain if in the post-complete state diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/SorterFunction.java b/src/main/java/io/reactivex/rxjava3/internal/util/SorterFunction.java index a62efd154f7..b74f1bccf65 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/SorterFunction.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/SorterFunction.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/SuppressAnimalSniffer.java b/src/main/java/io/reactivex/rxjava3/internal/util/SuppressAnimalSniffer.java index e57d8830369..b55fb0673b9 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/SuppressAnimalSniffer.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/SuppressAnimalSniffer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/internal/util/VolatileSizeArrayList.java b/src/main/java/io/reactivex/rxjava3/internal/util/VolatileSizeArrayList.java index 33e1e18a562..798a05a6dca 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/util/VolatileSizeArrayList.java +++ b/src/main/java/io/reactivex/rxjava3/internal/util/VolatileSizeArrayList.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/observables/ConnectableObservable.java b/src/main/java/io/reactivex/rxjava3/observables/ConnectableObservable.java index 19a083d7277..231d0357fea 100644 --- a/src/main/java/io/reactivex/rxjava3/observables/ConnectableObservable.java +++ b/src/main/java/io/reactivex/rxjava3/observables/ConnectableObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -32,22 +32,21 @@ * can wait for all intended {@link Observer}s to {@link Observable#subscribe} to the {@code Observable} * before the {@code Observable} begins emitting items. *

- * + * *

* When the upstream terminates, the {@code ConnectableObservable} remains in this terminated state and, - * depending on the actual underlying implementation, relays cached events to late {@link Observer}s. + * depending on the actual underlying implementation, relays cached events to late {@code Observer}s. * In order to reuse and restart this {@code ConnectableObservable}, the {@link #reset()} method has to be called. - * When called, this {@code ConnectableObservable} will appear as fresh, unconnected source to new {@link Observer}s. - * Disposing the connection will reset the {@code ConnectableFlowable} to its fresh state and there is no need to call - * {@code reset()} in this case. + * When called, this {@code ConnectableObservable} will appear as fresh, unconnected source to new {@code Observer}s. + * Disposing the connection will reset the {@code ConnectableObservable} to its fresh state and there is no need to call + * {@link #reset()} in this case. *

* Note that although {@link #connect()} and {@link #reset()} are safe to call from multiple threads, it is recommended * a dedicated thread or business logic manages the connection or resetting of a {@code ConnectableObservable} so that * there is no unwanted signal loss due to early {@code connect()} or {@code reset()} calls while {@code Observer}s are * still being subscribed to to this {@code ConnectableObservable} to receive signals from the get go. * - * @see RxJava Wiki: - * Connectable Observable Operators + * @see RxJava Wiki: Connectable Observable Operators * @param * the type of items emitted by the {@code ConnectableObservable} */ @@ -64,13 +63,14 @@ public abstract class ConnectableObservable extends Observable { * @param connection * the action that receives the connection subscription before the subscription to source happens * allowing the caller to synchronously disconnect a synchronous source + * @throws NullPointerException if {@code connection} is {@code null} * @see ReactiveX documentation: Connect */ @SchedulerSupport(SchedulerSupport.NONE) public abstract void connect(@NonNull Consumer connection); /** - * Resets this ConnectableObservable into its fresh state if it has terminated + * Resets this {@code ConnectableObservable} into its fresh state if it has terminated * or has been disposed. *

* Calling this method on a fresh or active {@code ConnectableObservable} has no effect. @@ -93,7 +93,7 @@ public abstract class ConnectableObservable extends Observable { *

The behavior is determined by the implementor of this abstract class.
* * - * @return the subscription representing the connection + * @return the {@link Disposable} representing the connection * @see ReactiveX documentation: Connect */ @NonNull @@ -105,13 +105,13 @@ public final Disposable connect() { } /** - * Returns an {@code Observable} that stays connected to this {@code ConnectableObservable} as long as there + * Returns an {@link Observable} that stays connected to this {@code ConnectableObservable} as long as there * is at least one subscription to this {@code ConnectableObservable}. *
*
Scheduler:
*
This {@code refCount} overload does not operate on any particular {@link Scheduler}.
*
- * @return an {@link Observable} + * @return a new {@code Observable} instance * @see ReactiveX documentation: RefCount * @see #refCount(int) * @see #refCount(long, TimeUnit) @@ -126,35 +126,37 @@ public Observable refCount() { /** * Connects to the upstream {@code ConnectableObservable} if the number of subscribed - * observers reaches the specified count and disconnect if all subscribers have unsubscribed. + * observers reaches the specified count and disconnect if all {@link Observer}s have unsubscribed. *
*
Scheduler:
*
This {@code refCount} overload does not operate on any particular {@link Scheduler}.
*
*

History: 2.1.14 - experimental - * @param subscriberCount the number of subscribers required to connect to the upstream - * @return the new Observable instance + * @param observerCount the number of {@code Observer}s required to connect to the upstream + * @return the new {@link Observable} instance + * @throws IllegalArgumentException if {@code observerCount} is non-positive * @since 2.2 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Observable refCount(int subscriberCount) { - return refCount(subscriberCount, 0, TimeUnit.NANOSECONDS, Schedulers.trampoline()); + public final Observable refCount(int observerCount) { + return refCount(observerCount, 0, TimeUnit.NANOSECONDS, Schedulers.trampoline()); } /** * Connects to the upstream {@code ConnectableObservable} if the number of subscribed * observers reaches 1 and disconnect after the specified - * timeout if all subscribers have unsubscribed. + * timeout if all {@link Observer}s have unsubscribed. *

*
Scheduler:
*
This {@code refCount} overload operates on the {@code computation} {@link Scheduler}.
*
*

History: 2.1.14 - experimental - * @param timeout the time to wait before disconnecting after all subscribers unsubscribed + * @param timeout the time to wait before disconnecting after all {@code Observer}s unsubscribed * @param unit the time unit of the timeout - * @return the new Observable instance + * @return the new {@link Observable} instance + * @throws NullPointerException if {@code unit} is {@code null} * @see #refCount(long, TimeUnit, Scheduler) * @since 2.2 */ @@ -168,16 +170,17 @@ public final Observable refCount(long timeout, @NonNull TimeUnit unit) { /** * Connects to the upstream {@code ConnectableObservable} if the number of subscribed * observers reaches 1 and disconnect after the specified - * timeout if all subscribers have unsubscribed. + * timeout if all {@link Observer}s have unsubscribed. *

*
Scheduler:
*
This {@code refCount} overload operates on the specified {@link Scheduler}.
*
*

History: 2.1.14 - experimental - * @param timeout the time to wait before disconnecting after all subscribers unsubscribed + * @param timeout the time to wait before disconnecting after all {@code Observer}s unsubscribed * @param unit the time unit of the timeout * @param scheduler the target scheduler to wait on before disconnecting - * @return the new Observable instance + * @return the new {@link Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -190,65 +193,67 @@ public final Observable refCount(long timeout, @NonNull TimeUnit unit, @NonNu /** * Connects to the upstream {@code ConnectableObservable} if the number of subscribed * observers reaches the specified count and disconnect after the specified - * timeout if all subscribers have unsubscribed. + * timeout if all {@link Observer}s have unsubscribed. *

*
Scheduler:
*
This {@code refCount} overload operates on the {@code computation} {@link Scheduler}.
*
*

History: 2.1.14 - experimental - * @param subscriberCount the number of subscribers required to connect to the upstream - * @param timeout the time to wait before disconnecting after all subscribers unsubscribed + * @param observerCount the number of {@code Observer}s required to connect to the upstream + * @param timeout the time to wait before disconnecting after all {@code Observer}s unsubscribed * @param unit the time unit of the timeout - * @return the new Observable instance + * @return the new {@link Observable} instance + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code observerCount} is non-positive * @see #refCount(int, long, TimeUnit, Scheduler) * @since 2.2 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull - public final Observable refCount(int subscriberCount, long timeout, @NonNull TimeUnit unit) { - return refCount(subscriberCount, timeout, unit, Schedulers.computation()); + public final Observable refCount(int observerCount, long timeout, @NonNull TimeUnit unit) { + return refCount(observerCount, timeout, unit, Schedulers.computation()); } /** * Connects to the upstream {@code ConnectableObservable} if the number of subscribed * observers reaches the specified count and disconnect after the specified - * timeout if all subscribers have unsubscribed. + * timeout if all {@link Observer}s have unsubscribed. *

*
Scheduler:
*
This {@code refCount} overload operates on the specified {@link Scheduler}.
*
*

History: 2.1.14 - experimental - * @param subscriberCount the number of subscribers required to connect to the upstream - * @param timeout the time to wait before disconnecting after all subscribers unsubscribed + * @param observerCount the number of {@code Observer}s required to connect to the upstream + * @param timeout the time to wait before disconnecting after all {@code Observer}s unsubscribed * @param unit the time unit of the timeout * @param scheduler the target scheduler to wait on before disconnecting - * @return the new Observable instance - * @throws IllegalArgumentException if {@code subscriberCount} is non-positive + * @return the new {@link Observable} instance * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code observerCount} is non-positive * @since 2.2 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable refCount(int subscriberCount, long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - ObjectHelper.verifyPositive(subscriberCount, "subscriberCount"); + public final Observable refCount(int observerCount, long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + ObjectHelper.verifyPositive(observerCount, "observerCount"); Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new ObservableRefCount<>(this, subscriberCount, timeout, unit, scheduler)); + return RxJavaPlugins.onAssembly(new ObservableRefCount<>(this, observerCount, timeout, unit, scheduler)); } /** - * Returns an Observable that automatically connects (at most once) to this ConnectableObservable - * when the first Observer subscribes. + * Returns an {@link Observable} that automatically connects (at most once) to this {@code ConnectableObservable} + * when the first {@link Observer} subscribes. *

* *

* The connection happens after the first subscription and happens at most once - * during the lifetime of the returned Observable. If this ConnectableObservable - * terminates, the connection is never renewed, no matter how Observers come + * during the lifetime of the returned {@code Observable}. If this {@code ConnectableObservable} + * terminates, the connection is never renewed, no matter how {@code Observer}s come * and go. Use {@link #refCount()} to renew a connection or dispose an active - * connection when all {@code Observer}s have disposed their {@code Disposable}s. + * connection when all {@code Observer}s have disposed their {@link Disposable}s. *

* This overload does not allow disconnecting the connection established via * {@link #connect(Consumer)}. Use the {@link #autoConnect(int, Consumer)} overload @@ -258,8 +263,8 @@ public final Observable refCount(int subscriberCount, long timeout, @NonNull *

{@code autoConnect} overload does not operate on any particular {@link Scheduler}.
* * - * @return an Observable that automatically connects to this ConnectableObservable - * when the first Observer subscribes + * @return a new {@code Observable} instance that automatically connects to this {@code ConnectableObservable} + * when the first {@code Observer} subscribes */ @NonNull @CheckReturnValue @@ -269,16 +274,16 @@ public Observable autoConnect() { } /** - * Returns an Observable that automatically connects (at most once) to this ConnectableObservable - * when the specified number of Observers subscribe to it. + * Returns an {@link Observable} that automatically connects (at most once) to this {@code ConnectableObservable} + * when the specified number of {@link Observer}s subscribe to it. *

* *

* The connection happens after the given number of subscriptions and happens at most once - * during the lifetime of the returned Observable. If this ConnectableObservable - * terminates, the connection is never renewed, no matter how Observers come + * during the lifetime of the returned {@code Observable}. If this {@code ConnectableObservable} + * terminates, the connection is never renewed, no matter how {@code Observer}s come * and go. Use {@link #refCount()} to renew a connection or dispose an active - * connection when all {@code Observer}s have disposed their {@code Disposable}s. + * connection when all {@code Observer}s have disposed their {@link Disposable}s. *

* This overload does not allow disconnecting the connection established via * {@link #connect(Consumer)}. Use the {@link #autoConnect(int, Consumer)} overload @@ -288,29 +293,29 @@ public Observable autoConnect() { *

{@code autoConnect} overload does not operate on any particular {@link Scheduler}.
* * - * @param numberOfSubscribers the number of subscribers to await before calling connect - * on the ConnectableObservable. A non-positive value indicates + * @param numberOfObservers the number of subscribers to await before calling connect + * on the {@code ConnectableObservable}. A non-positive value indicates * an immediate connection. - * @return an Observable that automatically connects to this ConnectableObservable - * when the specified number of Subscribers subscribe to it + * @return a new {@code Observable} instance that automatically connects to this {@code ConnectableObservable} + * when the specified number of {@code Observer}s subscribe to it */ @NonNull @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) - public Observable autoConnect(int numberOfSubscribers) { - return autoConnect(numberOfSubscribers, Functions.emptyConsumer()); + public Observable autoConnect(int numberOfObservers) { + return autoConnect(numberOfObservers, Functions.emptyConsumer()); } /** - * Returns an Observable that automatically connects (at most once) to this ConnectableObservable - * when the specified number of Subscribers subscribe to it and calls the - * specified callback with the Subscription associated with the established connection. + * Returns an {@link Observable} that automatically connects (at most once) to this {@code ConnectableObservable} + * when the specified number of {@link Observer}s subscribe to it and calls the + * specified callback with the {@link Disposable} associated with the established connection. *

* *

* The connection happens after the given number of subscriptions and happens at most once - * during the lifetime of the returned Observable. If this ConnectableObservable - * terminates, the connection is never renewed, no matter how Observers come + * during the lifetime of the returned {@code Observable}. If this {@code ConnectableObservable} + * terminates, the connection is never renewed, no matter how {@code Observer}s come * and go. Use {@link #refCount()} to renew a connection or dispose an active * connection when all {@code Observer}s have disposed their {@code Disposable}s. *

@@ -318,23 +323,25 @@ public Observable autoConnect(int numberOfSubscribers) { *
{@code autoConnect} overload does not operate on any particular {@link Scheduler}.
*
* - * @param numberOfSubscribers the number of subscribers to await before calling connect - * on the ConnectableObservable. A non-positive value indicates + * @param numberOfObservers the number of subscribers to await before calling connect + * on the {@code ConnectableObservable}. A non-positive value indicates * an immediate connection. - * @param connection the callback Consumer that will receive the Subscription representing the + * @param connection the callback {@link Consumer} that will receive the {@code Disposable} representing the * established connection - * @return an Observable that automatically connects to this ConnectableObservable - * when the specified number of Subscribers subscribe to it and calls the - * specified callback with the Subscription associated with the established connection + * @return a new {@code Observable} instance that automatically connects to this {@code ConnectableObservable} + * when the specified number of {@code Observer}s subscribe to it and calls the + * specified callback with the {@code Disposable} associated with the established connection + * @throws NullPointerException if {@code connection} is {@code null} */ @NonNull @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) - public Observable autoConnect(int numberOfSubscribers, @NonNull Consumer connection) { - if (numberOfSubscribers <= 0) { + public Observable autoConnect(int numberOfObservers, @NonNull Consumer connection) { + Objects.requireNonNull(connection, "connection is null"); + if (numberOfObservers <= 0) { this.connect(connection); return RxJavaPlugins.onAssembly(this); } - return RxJavaPlugins.onAssembly(new ObservableAutoConnect<>(this, numberOfSubscribers, connection)); + return RxJavaPlugins.onAssembly(new ObservableAutoConnect<>(this, numberOfObservers, connection)); } } diff --git a/src/main/java/io/reactivex/rxjava3/observables/GroupedObservable.java b/src/main/java/io/reactivex/rxjava3/observables/GroupedObservable.java index 489ee1d716c..baa35ce48dc 100644 --- a/src/main/java/io/reactivex/rxjava3/observables/GroupedObservable.java +++ b/src/main/java/io/reactivex/rxjava3/observables/GroupedObservable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.observables; import io.reactivex.rxjava3.annotations.Nullable; diff --git a/src/main/java/io/reactivex/rxjava3/observables/package-info.java b/src/main/java/io/reactivex/rxjava3/observables/package-info.java index 7fb2fc14544..93c6ad0c406 100644 --- a/src/main/java/io/reactivex/rxjava3/observables/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/observables/package-info.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ /** diff --git a/src/main/java/io/reactivex/rxjava3/observers/BaseTestConsumer.java b/src/main/java/io/reactivex/rxjava3/observers/BaseTestConsumer.java index 458325c280f..6b3a72fadbc 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/BaseTestConsumer.java +++ b/src/main/java/io/reactivex/rxjava3/observers/BaseTestConsumer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -54,6 +54,9 @@ public abstract class BaseTestConsumer> { */ protected boolean timeout; + /** + * Constructs a {@code BaseTestConsumer} with {@code CountDownLatch} set to 1. + */ public BaseTestConsumer() { this.values = new VolatileSizeArrayList<>(); this.errors = new VolatileSizeArrayList<>(); @@ -228,7 +231,7 @@ public final U assertNoErrors() { */ @NonNull public final U assertError(@NonNull Throwable error) { - return assertError(Functions.equalsWith(error)); + return assertError(Functions.equalsWith(error), true); } /** @@ -240,7 +243,7 @@ public final U assertError(@NonNull Throwable error) { @SuppressWarnings({ "unchecked", "rawtypes" }) @NonNull public final U assertError(@NonNull Class errorClass) { - return (U)assertError((Predicate)Functions.isInstanceOf(errorClass)); + return (U)assertError((Predicate)Functions.isInstanceOf(errorClass), true); } /** @@ -251,9 +254,14 @@ public final U assertError(@NonNull Class errorClass) { * and should return {@code true} for expected errors. * @return this */ - @SuppressWarnings("unchecked") @NonNull public final U assertError(@NonNull Predicate errorPredicate) { + return assertError(errorPredicate, false); + } + + @SuppressWarnings("unchecked") + @NonNull + private U assertError(@NonNull Predicate errorPredicate, boolean exact) { int s = errors.size(); if (s == 0) { throw fail("No errors"); @@ -274,10 +282,16 @@ public final U assertError(@NonNull Predicate errorPredicate) { if (found) { if (s != 1) { - throw fail("Error present but other errors as well"); + if (exact) { + throw fail("Error present but other errors as well"); + } + throw fail("One error passed the predicate but other errors are present as well"); } } else { - throw fail("Error not present"); + if (exact) { + throw fail("Error not present"); + } + throw fail("No error(s) passed the predicate"); } return (U)this; } @@ -293,11 +307,11 @@ public final U assertError(@NonNull Predicate errorPredicate) { public final U assertValue(@NonNull T value) { int s = values.size(); if (s != 1) { - throw fail("expected: " + valueAndClass(value) + " but was: " + values); + throw fail("\nexpected: " + valueAndClass(value) + "\ngot: " + values); } T v = values.get(0); if (!Objects.equals(value, v)) { - throw fail("expected: " + valueAndClass(value) + " but was: " + valueAndClass(v)); + throw fail("\nexpected: " + valueAndClass(value) + "\ngot: " + valueAndClass(v)); } return (U)this; } @@ -316,7 +330,7 @@ public final U assertValue(@NonNull Predicate valuePredicate) { assertValueAt(0, valuePredicate); if (values.size() > 1) { - throw fail("Value present but other values as well"); + throw fail("The first value passed the predicate but this consumer received more than one value"); } return (U)this; @@ -339,13 +353,14 @@ public final U assertValueAt(int index, @NonNull T value) { throw fail("No values"); } - if (index >= s) { - throw fail("Invalid index: " + index); + if (index < 0 || index >= s) { + throw fail("Index " + index + " is out of range [0, " + s + ")"); } T v = values.get(index); if (!Objects.equals(value, v)) { - throw fail("expected: " + valueAndClass(value) + " but was: " + valueAndClass(v)); + throw fail("\nexpected: " + valueAndClass(value) + "\ngot: " + valueAndClass(v) + + "; Value at position " + index + " differ"); } return (U)this; } @@ -367,14 +382,15 @@ public final U assertValueAt(int index, @NonNull Predicate valuePredicate) { throw fail("No values"); } - if (index >= values.size()) { - throw fail("Invalid index: " + index); + if (index < 0 || index >= s) { + throw fail("Index " + index + " is out of range [0, " + s + ")"); } boolean found = false; + T v = values.get(index); try { - if (valuePredicate.test(values.get(index))) { + if (valuePredicate.test(v)) { found = true; } } catch (Throwable ex) { @@ -382,7 +398,7 @@ public final U assertValueAt(int index, @NonNull Predicate valuePredicate) { } if (!found) { - throw fail("Value not present"); + throw fail("Value " + valueAndClass(v) + " at position " + index + " did not pass the predicate"); } return (U)this; } @@ -410,7 +426,7 @@ public static String valueAndClass(@Nullable Object o) { public final U assertValueCount(int count) { int s = values.size(); if (s != count) { - throw fail("Value counts differ; expected: " + count + " but was: " + s); + throw fail("\nexpected: " + count + "\ngot: " + s + "; Value counts differ"); } return (U)this; } @@ -435,14 +451,15 @@ public final U assertNoValues() { public final U assertValues(@NonNull T... values) { int s = this.values.size(); if (s != values.length) { - throw fail("Value count differs; expected: " + values.length + " " + Arrays.toString(values) - + " but was: " + s + " " + this.values); + throw fail("\nexpected: " + values.length + " " + Arrays.toString(values) + + "\ngot: " + s + " " + this.values + "; Value count differs"); } for (int i = 0; i < s; i++) { T v = this.values.get(i); T u = values[i]; if (!Objects.equals(u, v)) { - throw fail("Values at position " + i + " differ; expected: " + valueAndClass(u) + " but was: " + valueAndClass(v)); + throw fail("\nexpected: " + valueAndClass(u) + "\ngot: " + valueAndClass(v) + + "; Value at position " + i + " differ"); } } return (U)this; @@ -489,7 +506,8 @@ public final U assertValueSequence(@NonNull Iterable sequence) { T v = actualIterator.next(); if (!Objects.equals(u, v)) { - throw fail("Values at position " + i + " differ; expected: " + valueAndClass(u) + " but was: " + valueAndClass(v)); + throw fail("\nexpected: " + valueAndClass(u) + "\ngot: " + valueAndClass(v) + + "; Value at position " + i + " differ"); } i++; } diff --git a/src/main/java/io/reactivex/rxjava3/observers/DefaultObserver.java b/src/main/java/io/reactivex/rxjava3/observers/DefaultObserver.java index 42cd69e79cd..29d1f16d007 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/DefaultObserver.java +++ b/src/main/java/io/reactivex/rxjava3/observers/DefaultObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/observers/DisposableCompletableObserver.java b/src/main/java/io/reactivex/rxjava3/observers/DisposableCompletableObserver.java index 940654b622f..20bf6d59d59 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/DisposableCompletableObserver.java +++ b/src/main/java/io/reactivex/rxjava3/observers/DisposableCompletableObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/observers/DisposableMaybeObserver.java b/src/main/java/io/reactivex/rxjava3/observers/DisposableMaybeObserver.java index 092994e8180..6ea1d26e977 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/DisposableMaybeObserver.java +++ b/src/main/java/io/reactivex/rxjava3/observers/DisposableMaybeObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/observers/DisposableObserver.java b/src/main/java/io/reactivex/rxjava3/observers/DisposableObserver.java index ff2eba7758c..d4e6d5f5d8a 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/DisposableObserver.java +++ b/src/main/java/io/reactivex/rxjava3/observers/DisposableObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/observers/DisposableSingleObserver.java b/src/main/java/io/reactivex/rxjava3/observers/DisposableSingleObserver.java index 56e5c543b72..9126332b218 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/DisposableSingleObserver.java +++ b/src/main/java/io/reactivex/rxjava3/observers/DisposableSingleObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/observers/LambdaConsumerIntrospection.java b/src/main/java/io/reactivex/rxjava3/observers/LambdaConsumerIntrospection.java index e3f5c46cfe1..293847979ec 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/LambdaConsumerIntrospection.java +++ b/src/main/java/io/reactivex/rxjava3/observers/LambdaConsumerIntrospection.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/observers/ResourceCompletableObserver.java b/src/main/java/io/reactivex/rxjava3/observers/ResourceCompletableObserver.java index df05fe01692..339692d7560 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/ResourceCompletableObserver.java +++ b/src/main/java/io/reactivex/rxjava3/observers/ResourceCompletableObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/observers/ResourceMaybeObserver.java b/src/main/java/io/reactivex/rxjava3/observers/ResourceMaybeObserver.java index 22345e60ced..e9df1c3edcf 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/ResourceMaybeObserver.java +++ b/src/main/java/io/reactivex/rxjava3/observers/ResourceMaybeObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/observers/ResourceObserver.java b/src/main/java/io/reactivex/rxjava3/observers/ResourceObserver.java index f0810f4c5e7..0238dd5a176 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/ResourceObserver.java +++ b/src/main/java/io/reactivex/rxjava3/observers/ResourceObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/observers/ResourceSingleObserver.java b/src/main/java/io/reactivex/rxjava3/observers/ResourceSingleObserver.java index efebfaa85c4..b1b90495241 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/ResourceSingleObserver.java +++ b/src/main/java/io/reactivex/rxjava3/observers/ResourceSingleObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/observers/SafeObserver.java b/src/main/java/io/reactivex/rxjava3/observers/SafeObserver.java index c3935e79dc9..4a72e5b80e1 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/SafeObserver.java +++ b/src/main/java/io/reactivex/rxjava3/observers/SafeObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.observers; import io.reactivex.rxjava3.annotations.NonNull; diff --git a/src/main/java/io/reactivex/rxjava3/observers/SerializedObserver.java b/src/main/java/io/reactivex/rxjava3/observers/SerializedObserver.java index e0d32fbd7ae..062a3b6abf7 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/SerializedObserver.java +++ b/src/main/java/io/reactivex/rxjava3/observers/SerializedObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.observers; import io.reactivex.rxjava3.annotations.NonNull; diff --git a/src/main/java/io/reactivex/rxjava3/observers/TestObserver.java b/src/main/java/io/reactivex/rxjava3/observers/TestObserver.java index 44b129fdab4..8142747ec1f 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/TestObserver.java +++ b/src/main/java/io/reactivex/rxjava3/observers/TestObserver.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.observers; import java.util.concurrent.atomic.AtomicReference; diff --git a/src/main/java/io/reactivex/rxjava3/observers/package-info.java b/src/main/java/io/reactivex/rxjava3/observers/package-info.java index dbf39cbef2b..09f56f3eb03 100644 --- a/src/main/java/io/reactivex/rxjava3/observers/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/observers/package-info.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ /** @@ -23,7 +20,8 @@ *

* Available observer variants *
- * + *
+ * * * * diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/ConditionalSubscriber.java b/src/main/java/io/reactivex/rxjava3/operators/ConditionalSubscriber.java similarity index 73% rename from src/main/java/io/reactivex/rxjava3/internal/fuseable/ConditionalSubscriber.java rename to src/main/java/io/reactivex/rxjava3/operators/ConditionalSubscriber.java index 2b4fe68be1f..0880d125447 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/ConditionalSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/operators/ConditionalSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -11,26 +11,27 @@ * the License for the specific language governing permissions and limitations under the License. */ -package io.reactivex.rxjava3.internal.fuseable; +package io.reactivex.rxjava3.operators; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.FlowableSubscriber; /** - * A Subscriber with an additional {@link #tryOnNext(Object)} method that - * tells the caller the specified value has been accepted or - * not. + * A {@link FlowableSubscriber} with an additional {@link #tryOnNext(Object)} method that + * tells the caller the specified value has been accepted or not. * *

This allows certain queue-drain or source-drain operators * to avoid requesting 1 on behalf of a dropped value. * * @param the value type + * @since 3.1.1 */ -public interface ConditionalSubscriber extends FlowableSubscriber { +public interface ConditionalSubscriber<@NonNull T> extends FlowableSubscriber { /** * Conditionally takes the value. * @param t the value to deliver * @return true if the value has been accepted, false if the value has been rejected * and the next value can be sent immediately */ - boolean tryOnNext(T t); + boolean tryOnNext(@NonNull T t); } diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/QueueDisposable.java b/src/main/java/io/reactivex/rxjava3/operators/QueueDisposable.java similarity index 65% rename from src/main/java/io/reactivex/rxjava3/internal/fuseable/QueueDisposable.java rename to src/main/java/io/reactivex/rxjava3/operators/QueueDisposable.java index 2becb58d43a..97096064d90 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/QueueDisposable.java +++ b/src/main/java/io/reactivex/rxjava3/operators/QueueDisposable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,15 +10,15 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ -package io.reactivex.rxjava3.internal.fuseable; -import java.util.Queue; +package io.reactivex.rxjava3.operators; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.disposables.Disposable; /** - * An interface extending Queue and Disposable and allows negotiating - * the fusion mode between subsequent operators of the {@code Observable} base reactive type. + * An interface extending {@link SimpleQueue} and {@link Disposable} and allows negotiating + * the fusion mode between subsequent operators of the {@link io.reactivex.rxjava3.core.Observable Observable} base reactive type. *

* The negotiation happens in subscription time when the upstream * calls the {@code onSubscribe} with an instance of this interface. The @@ -26,30 +26,32 @@ * with the appropriate mode before calling {@code request()}. *

* In synchronous fusion, all upstream values are either already available or is generated - * when {@link #poll()} is called synchronously. When the {@link #poll()} returns null, + * when {@link #poll()} is called synchronously. When the {@link #poll()} returns {@code null}, * that is the indication if a terminated stream. In this mode, the upstream won't call the onXXX methods. *

* In asynchronous fusion, upstream values may become available to {@link #poll()} eventually. - * Upstream signals onError() and onComplete() as usual but onNext may not actually contain - * the upstream value but have {@code null} instead. Downstream should treat such onNext as indication - * that {@link #poll()} can be called. + * Upstream signals {@code onError()} and {@code onComplete()} as usual, however, + * {@code onNext} will be called with {@code null} instead of the actual value. + * Downstream should treat such onNext as indication that {@link #poll()} can be called. *

- * The general rules for consuming the {@link Queue} interface: + * The general rules for consuming the {@link SimpleQueue} interface: *

    - *
  • {@link #poll()} has to be called sequentially (from within a serializing drain-loop).
  • + *
  • {@link #poll()} and {@link #clear()} has to be called sequentially (from within a serializing drain-loop).
  • *
  • In addition, callers of {@link #poll()} should be prepared to catch exceptions.
  • *
  • Due to how computation attaches to the {@link #poll()}, {@link #poll()} may return * {@code null} even if a preceding {@link #isEmpty()} returned false.
  • *
*

* Implementations should only allow calling the following methods and the rest of the - * {@link Queue} interface methods should throw {@link UnsupportedOperationException}: + * {@link SimpleQueue} interface methods should throw {@link UnsupportedOperationException}: *

    *
  • {@link #poll()}
  • *
  • {@link #isEmpty()}
  • *
  • {@link #clear()}
  • *
* @param the value type transmitted through the queue + * @see QueueSubscription + * @since 3.1.1 */ -public interface QueueDisposable extends QueueFuseable, Disposable { +public interface QueueDisposable<@NonNull T> extends QueueFuseable, Disposable { } diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/QueueFuseable.java b/src/main/java/io/reactivex/rxjava3/operators/QueueFuseable.java similarity index 92% rename from src/main/java/io/reactivex/rxjava3/internal/fuseable/QueueFuseable.java rename to src/main/java/io/reactivex/rxjava3/operators/QueueFuseable.java index fadc824cc77..d295d12f0db 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/QueueFuseable.java +++ b/src/main/java/io/reactivex/rxjava3/operators/QueueFuseable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -11,13 +11,16 @@ * the License for the specific language governing permissions and limitations under the License. */ -package io.reactivex.rxjava3.internal.fuseable; +package io.reactivex.rxjava3.operators; + +import io.reactivex.rxjava3.annotations.NonNull; /** - * Represents a SimpleQueue plus the means and constants for requesting a fusion mode. + * Represents a {@link SimpleQueue} plus the means and constants for requesting a fusion mode. * @param the value type returned by the SimpleQueue.poll() + * @since 3.1.1 */ -public interface QueueFuseable extends SimpleQueue { +public interface QueueFuseable<@NonNull T> extends SimpleQueue { /** * Returned by the {@link #requestFusion(int)} if the upstream doesn't support * the requested mode. diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/QueueSubscription.java b/src/main/java/io/reactivex/rxjava3/operators/QueueSubscription.java similarity index 65% rename from src/main/java/io/reactivex/rxjava3/internal/fuseable/QueueSubscription.java rename to src/main/java/io/reactivex/rxjava3/operators/QueueSubscription.java index 87599a6e401..eae89229927 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/QueueSubscription.java +++ b/src/main/java/io/reactivex/rxjava3/operators/QueueSubscription.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,15 +10,16 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ -package io.reactivex.rxjava3.internal.fuseable; -import java.util.Queue; +package io.reactivex.rxjava3.operators; import org.reactivestreams.Subscription; +import io.reactivex.rxjava3.annotations.NonNull; + /** - * An interface extending Queue and Subscription and allows negotiating - * the fusion mode between subsequent operators of the {@code Flowable} base reactive type. + * An interface extending {@link SimpleQueue} and {@link Subscription} and allows negotiating + * the fusion mode between subsequent operators of the {@link io.reactivex.rxjava3.core.Flowable Flowable} base reactive type. *

* The negotiation happens in subscription time when the upstream * calls the {@code onSubscribe} with an instance of this interface. The @@ -31,27 +32,30 @@ * in this mode. In this mode, the upstream won't call the onXXX methods. *

* In asynchronous fusion, upstream values may become available to {@link #poll()} eventually. - * Upstream signals onError() and onComplete() as usual but onNext may not actually contain - * the upstream value but have {@code null} instead. Downstream should treat such onNext as indication - * that {@link #poll()} can be called. In this mode, the downstream still has to call {@link #request(long)} + * Upstream signals {@code onError()} and {@code onComplete()} as usual, however, + * {@code onNext} will be called with {@code null} instead of the actual value. + * Downstream should treat such onNext as indication that {@link #poll()} can be called. + * In this mode, the downstream still has to call {@link #request(long)} * to indicate it is prepared to receive more values. *

- * The general rules for consuming the {@link Queue} interface: + * The general rules for consuming the {@link SimpleQueue} interface: *

    - *
  • {@link #poll()} has to be called sequentially (from within a serializing drain-loop).
  • + *
  • {@link #poll()} and {@link #clear()} has to be called sequentially (from within a serializing drain-loop).
  • *
  • In addition, callers of {@link #poll()} should be prepared to catch exceptions.
  • *
  • Due to how computation attaches to the {@link #poll()}, {@link #poll()} may return * {@code null} even if a preceding {@link #isEmpty()} returned false.
  • *
*

* Implementations should only allow calling the following methods and the rest of the - * {@link Queue} interface methods should throw {@link UnsupportedOperationException}: + * {@link SimpleQueue} interface methods should throw {@link UnsupportedOperationException}: *

    *
  • {@link #poll()}
  • *
  • {@link #isEmpty()}
  • *
  • {@link #clear()}
  • *
* @param the value type transmitted through the queue + * @see QueueDisposable + * @since 3.1.1 */ -public interface QueueSubscription extends QueueFuseable, Subscription { +public interface QueueSubscription<@NonNull T> extends QueueFuseable, Subscription { } diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/ScalarSupplier.java b/src/main/java/io/reactivex/rxjava3/operators/ScalarSupplier.java similarity index 88% rename from src/main/java/io/reactivex/rxjava3/internal/fuseable/ScalarSupplier.java rename to src/main/java/io/reactivex/rxjava3/operators/ScalarSupplier.java index fc0d12323f7..9b79c5c1020 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/ScalarSupplier.java +++ b/src/main/java/io/reactivex/rxjava3/operators/ScalarSupplier.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,8 +10,10 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ -package io.reactivex.rxjava3.internal.fuseable; +package io.reactivex.rxjava3.operators; + +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.functions.Supplier; /** @@ -28,9 +30,10 @@ * single-element sources uniformly. *

* @param the scalar value type held by the implementing reactive type + * @since 3.1.1 */ @FunctionalInterface -public interface ScalarSupplier extends Supplier { +public interface ScalarSupplier<@NonNull T> extends Supplier { // overridden to remove the throws Throwable @Override diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/SimplePlainQueue.java b/src/main/java/io/reactivex/rxjava3/operators/SimplePlainQueue.java similarity index 72% rename from src/main/java/io/reactivex/rxjava3/internal/fuseable/SimplePlainQueue.java rename to src/main/java/io/reactivex/rxjava3/operators/SimplePlainQueue.java index 37085802703..7e0cac21f35 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/SimplePlainQueue.java +++ b/src/main/java/io/reactivex/rxjava3/operators/SimplePlainQueue.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -11,16 +11,17 @@ * the License for the specific language governing permissions and limitations under the License. */ -package io.reactivex.rxjava3.internal.fuseable; +package io.reactivex.rxjava3.operators; -import io.reactivex.rxjava3.annotations.Nullable; +import io.reactivex.rxjava3.annotations.*; /** - * Override of the SimpleQueue interface with no throws Exception on poll(). + * Override of the {@link SimpleQueue} interface with no {@code throws Throwable} on {@code poll()}. * * @param the value type to offer and poll, not null + * @since 3.1.1 */ -public interface SimplePlainQueue extends SimpleQueue { +public interface SimplePlainQueue<@NonNull T> extends SimpleQueue { @Nullable @Override diff --git a/src/main/java/io/reactivex/rxjava3/internal/fuseable/SimpleQueue.java b/src/main/java/io/reactivex/rxjava3/operators/SimpleQueue.java similarity index 83% rename from src/main/java/io/reactivex/rxjava3/internal/fuseable/SimpleQueue.java rename to src/main/java/io/reactivex/rxjava3/operators/SimpleQueue.java index 29af5299d88..a10b7f9a43c 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/fuseable/SimpleQueue.java +++ b/src/main/java/io/reactivex/rxjava3/operators/SimpleQueue.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -11,19 +11,24 @@ * the License for the specific language governing permissions and limitations under the License. */ -package io.reactivex.rxjava3.internal.fuseable; +package io.reactivex.rxjava3.operators; import io.reactivex.rxjava3.annotations.*; /** - * A minimalist queue interface without the method bloat of java.util.Collection and java.util.Queue. + * A simplified interface for offering, polling and clearing a queue. + *

+ * This interface does not define most of the {@link java.util.Collection} + * or {@link java.util.Queue} methods as the intended usage of {@code SimpleQueue} + * does not require support for iteration or introspection. * * @param the value type to offer and poll, not null + * @since 3.1.1 */ -public interface SimpleQueue { +public interface SimpleQueue<@NonNull T> { /** - * Atomically enqueue a single. + * Atomically enqueue a single value. * @param value the value to enqueue, not null * @return true if successful, false if the value was not enqueued * likely due to reaching the queue capacity) diff --git a/src/main/java/io/reactivex/rxjava3/internal/queue/SpscArrayQueue.java b/src/main/java/io/reactivex/rxjava3/operators/SpscArrayQueue.java similarity index 93% rename from src/main/java/io/reactivex/rxjava3/internal/queue/SpscArrayQueue.java rename to src/main/java/io/reactivex/rxjava3/operators/SpscArrayQueue.java index c86a109f81c..1e4c2d4f110 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/queue/SpscArrayQueue.java +++ b/src/main/java/io/reactivex/rxjava3/operators/SpscArrayQueue.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,12 +16,11 @@ * https://github.com/JCTools/JCTools/blob/master/jctools-core/src/main/java/org/jctools/queues/atomic */ -package io.reactivex.rxjava3.internal.queue; +package io.reactivex.rxjava3.operators; import java.util.concurrent.atomic.*; import io.reactivex.rxjava3.annotations.Nullable; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; import io.reactivex.rxjava3.internal.util.Pow2; /** @@ -37,6 +36,7 @@ * This implementation is wait free. * * @param the element type of the queue + * @since 3.1.1 */ public final class SpscArrayQueue extends AtomicReferenceArray implements SimplePlainQueue { private static final long serialVersionUID = -1296597691183856449L; @@ -47,6 +47,12 @@ public final class SpscArrayQueue extends AtomicReferenceArray implements final AtomicLong consumerIndex; final int lookAheadStep; + /** + * Constructs an array-backed queue with the given capacity rounded + * up to the next power of 2 size. + * @param capacity the maximum number of elements the queue would hold, + * rounded up to the next power of 2 + */ public SpscArrayQueue(int capacity) { super(Pow2.roundToPowerOfTwo(capacity)); this.mask = length() - 1; diff --git a/src/main/java/io/reactivex/rxjava3/internal/queue/SpscLinkedArrayQueue.java b/src/main/java/io/reactivex/rxjava3/operators/SpscLinkedArrayQueue.java similarity index 95% rename from src/main/java/io/reactivex/rxjava3/internal/queue/SpscLinkedArrayQueue.java rename to src/main/java/io/reactivex/rxjava3/operators/SpscLinkedArrayQueue.java index 2bd61dcc154..97fac2253ab 100644 --- a/src/main/java/io/reactivex/rxjava3/internal/queue/SpscLinkedArrayQueue.java +++ b/src/main/java/io/reactivex/rxjava3/operators/SpscLinkedArrayQueue.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,18 +16,18 @@ * https://github.com/JCTools/JCTools/blob/master/jctools-core/src/main/java/org/jctools/queues/atomic */ -package io.reactivex.rxjava3.internal.queue; +package io.reactivex.rxjava3.operators; import java.util.concurrent.atomic.*; import io.reactivex.rxjava3.annotations.Nullable; -import io.reactivex.rxjava3.internal.fuseable.SimplePlainQueue; import io.reactivex.rxjava3.internal.util.Pow2; /** * A single-producer single-consumer array-backed queue which can allocate new arrays in case the consumer is slower * than the producer. * @param the contained value type + * @since 3.1.1 */ public final class SpscLinkedArrayQueue implements SimplePlainQueue { static final int MAX_LOOK_AHEAD_STEP = Integer.getInteger("jctools.spsc.max.lookahead.step", 4096); @@ -45,6 +45,11 @@ public final class SpscLinkedArrayQueue implements SimplePlainQueue { private static final Object HAS_NEXT = new Object(); + /** + * Constructs a linked array-based queue instance with the given + * island size rounded up to the next power of 2. + * @param bufferSize the maximum number of elements per island + */ public SpscLinkedArrayQueue(final int bufferSize) { int p2capacity = Pow2.roundToPowerOfTwo(Math.max(8, bufferSize)); int mask = p2capacity - 1; @@ -160,7 +165,13 @@ private T newBufferPoll(AtomicReferenceArray nextBuffer, final long inde return n; } + /** + * Returns the next element in this queue without removing it or {@code null} + * if this queue is empty + * @return the next element or {@code null} + */ @SuppressWarnings("unchecked") + @Nullable public T peek() { final AtomicReferenceArray buffer = consumerBuffer; final long index = lpConsumerIndex(); @@ -186,6 +197,10 @@ public void clear() { while (poll() != null || !isEmpty()) { } // NOPMD } + /** + * Returns the number of elements in the queue. + * @return the number of elements in the queue + */ public int size() { /* * It is possible for a thread to be interrupted or reschedule between the read of the producer and diff --git a/src/main/java/io/reactivex/rxjava3/operators/package-info.java b/src/main/java/io/reactivex/rxjava3/operators/package-info.java new file mode 100644 index 00000000000..93e1ca05be7 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava3/operators/package-info.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +/** + * Classes and interfaces for writing advanced operators within and outside RxJava. + */ + +package io.reactivex.rxjava3.operators; \ No newline at end of file diff --git a/src/main/java/io/reactivex/rxjava3/parallel/ParallelFailureHandling.java b/src/main/java/io/reactivex/rxjava3/parallel/ParallelFailureHandling.java index 9e78d698e89..ce0496651e5 100644 --- a/src/main/java/io/reactivex/rxjava3/parallel/ParallelFailureHandling.java +++ b/src/main/java/io/reactivex/rxjava3/parallel/ParallelFailureHandling.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/parallel/ParallelFlowable.java b/src/main/java/io/reactivex/rxjava3/parallel/ParallelFlowable.java index ea09fb53d46..8d5414d27cf 100644 --- a/src/main/java/io/reactivex/rxjava3/parallel/ParallelFlowable.java +++ b/src/main/java/io/reactivex/rxjava3/parallel/ParallelFlowable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,6 +20,7 @@ import io.reactivex.rxjava3.annotations.*; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.MissingBackpressureException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.*; import io.reactivex.rxjava3.internal.jdk8.*; @@ -42,7 +43,7 @@ public abstract class ParallelFlowable<@NonNull T> { /** - * Subscribes an array of Subscribers to this ParallelFlowable and triggers + * Subscribes an array of {@link Subscriber}s to this {@code ParallelFlowable} and triggers * the execution chain for all 'rails'. *
*
Backpressure:
@@ -52,7 +53,8 @@ public abstract class ParallelFlowable<@NonNull T> { *
* * @param subscribers the subscribers array to run in parallel, the number - * of items must be equal to the parallelism level of this ParallelFlowable + * of items must be equal to the parallelism level of this {@code ParallelFlowable} + * @throws NullPointerException if {@code subscribers} is {@code null} * @see #parallelism() */ @BackpressureSupport(BackpressureKind.SPECIAL) @@ -60,24 +62,27 @@ public abstract class ParallelFlowable<@NonNull T> { public abstract void subscribe(@NonNull Subscriber[] subscribers); /** - * Returns the number of expected parallel Subscribers. - * @return the number of expected parallel Subscribers + * Returns the number of expected parallel {@link Subscriber}s. + * @return the number of expected parallel {@code Subscriber}s */ @CheckReturnValue public abstract int parallelism(); /** - * Validates the number of subscribers and returns true if their number - * matches the parallelism level of this ParallelFlowable. + * Validates the number of subscribers and returns {@code true} if their number + * matches the parallelism level of this {@code ParallelFlowable}. * - * @param subscribers the array of Subscribers - * @return true if the number of subscribers equals to the parallelism level + * @param subscribers the array of {@link Subscriber}s + * @return {@code true} if the number of subscribers equals to the parallelism level + * @throws NullPointerException if {@code subscribers} is {@code null} + * @throws IllegalArgumentException if {@code subscribers.length} is different from {@link #parallelism()} */ - protected final boolean validate(@NonNull Subscriber[] subscribers) { + protected final boolean validate(@NonNull Subscriber<@NonNull ?>[] subscribers) { + Objects.requireNonNull(subscribers, "subscribers is null"); int p = parallelism(); if (subscribers.length != p) { Throwable iae = new IllegalArgumentException("parallelism = " + p + ", subscribers = " + subscribers.length); - for (Subscriber s : subscribers) { + for (Subscriber<@NonNull ?> s : subscribers) { EmptySubscription.error(iae, s); } return false; @@ -86,7 +91,7 @@ protected final boolean validate(@NonNull Subscriber[] subscribers) { } /** - * Take a Publisher and prepare to consume it on multiple 'rails' (number of CPUs) + * Take a {@link Publisher} and prepare to consume it on multiple 'rails' (number of CPUs) * in a round-robin fashion. *
*
Backpressure:
@@ -97,19 +102,20 @@ protected final boolean validate(@NonNull Subscriber[] subscribers) { *
{@code from} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param source the source Publisher - * @return the ParallelFlowable instance + * @param source the source {@code Publisher} + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code source} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.FULL) - public static ParallelFlowable from(@NonNull Publisher source) { + public static <@NonNull T> ParallelFlowable from(@NonNull Publisher source) { return from(source, Runtime.getRuntime().availableProcessors(), Flowable.bufferSize()); } /** - * Take a Publisher and prepare to consume it on parallelism number of 'rails' in a round-robin fashion. + * Take a {@link Publisher} and prepare to consume it on parallelism number of 'rails' in a round-robin fashion. *
*
Backpressure:
*
The operator honors the backpressure of the parallel rails and @@ -119,9 +125,11 @@ public static ParallelFlowable from(@NonNull Publisher sourc *
{@code from} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param source the source Publisher + * @param source the source {@code Publisher} * @param parallelism the number of parallel rails - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code source} is {@code null} + * @throws IllegalArgumentException if {@code parallelism} is non-positive */ @CheckReturnValue @NonNull @@ -132,9 +140,9 @@ public static ParallelFlowable from(@NonNull Publisher sourc } /** - * Take a Publisher and prepare to consume it on parallelism number of 'rails' , + * Take a {@link Publisher} and prepare to consume it on parallelism number of 'rails' , * possibly ordered and round-robin fashion and use custom prefetch amount and queue - * for dealing with the source Publisher's values. + * for dealing with the source {@code Publisher}'s values. *
*
Backpressure:
*
The operator honors the backpressure of the parallel rails and @@ -144,11 +152,13 @@ public static ParallelFlowable from(@NonNull Publisher sourc *
{@code from} does not operate by default on a particular {@link Scheduler}.
*
* @param the value type - * @param source the source Publisher + * @param source the source {@code Publisher} * @param parallelism the number of parallel rails * @param prefetch the number of values to prefetch from the source * the source until there is a rail ready to process it. - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code source} is {@code null} + * @throws IllegalArgumentException if {@code parallelism} or {@code prefetch} is non-positive */ @CheckReturnValue @NonNull @@ -156,7 +166,7 @@ public static ParallelFlowable from(@NonNull Publisher sourc @BackpressureSupport(BackpressureKind.FULL) public static <@NonNull T> ParallelFlowable from(@NonNull Publisher source, int parallelism, int prefetch) { - Objects.requireNonNull(source, "source"); + Objects.requireNonNull(source, "source is null"); ObjectHelper.verifyPositive(parallelism, "parallelism"); ObjectHelper.verifyPositive(prefetch, "prefetch"); @@ -166,7 +176,7 @@ public static ParallelFlowable from(@NonNull Publisher sourc /** * Maps the source values on each 'rail' to another value. *

- * Note that the same mapper function may be called from multiple threads concurrently. + * Note that the same {@code mapper} function may be called from multiple threads concurrently. *

*
Backpressure:
*
The operator is a pass-through for backpressure and the behavior @@ -176,14 +186,15 @@ public static ParallelFlowable from(@NonNull Publisher sourc *
* @param the output value type * @param mapper the mapper function turning Ts into Rs. - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.PASS_THROUGH) - public final ParallelFlowable map(@NonNull Function mapper) { - Objects.requireNonNull(mapper, "mapper"); + public final <@NonNull R> ParallelFlowable map(@NonNull Function mapper) { + Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new ParallelMap<>(this, mapper)); } @@ -191,7 +202,7 @@ public final ParallelFlowable map(@NonNull Function - * Note that the same mapper function may be called from multiple threads concurrently. + * Note that the same {@code mapper} function may be called from multiple threads concurrently. *
*
Backpressure:
*
The operator is a pass-through for backpressure and the behavior @@ -203,16 +214,17 @@ public final ParallelFlowable map(@NonNull Function the output value type * @param mapper the mapper function turning Ts into Rs. * @param errorHandler the enumeration that defines how to handle errors thrown - * from the mapper function - * @return the new ParallelFlowable instance + * from the {@code mapper} function + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code mapper} or {@code errorHandler} is {@code null} * @since 2.2 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.PASS_THROUGH) - public final ParallelFlowable map(@NonNull Function mapper, @NonNull ParallelFailureHandling errorHandler) { - Objects.requireNonNull(mapper, "mapper"); + public final <@NonNull R> ParallelFlowable map(@NonNull Function mapper, @NonNull ParallelFailureHandling errorHandler) { + Objects.requireNonNull(mapper, "mapper is null"); Objects.requireNonNull(errorHandler, "errorHandler is null"); return RxJavaPlugins.onAssembly(new ParallelMapTry<>(this, mapper, errorHandler)); } @@ -221,7 +233,7 @@ public final ParallelFlowable map(@NonNull Function - * Note that the same mapper function may be called from multiple threads concurrently. + * Note that the same {@code mapper} function may be called from multiple threads concurrently. *
*
Backpressure:
*
The operator is a pass-through for backpressure and the behavior @@ -233,17 +245,18 @@ public final ParallelFlowable map(@NonNull Function the output value type * @param mapper the mapper function turning Ts into Rs. * @param errorHandler the function called with the current repeat count and - * failure Throwable and should return one of the {@link ParallelFailureHandling} + * failure {@link Throwable} and should return one of the {@link ParallelFailureHandling} * enumeration values to indicate how to proceed. - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code mapper} or {@code errorHandler} is {@code null} * @since 2.2 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.PASS_THROUGH) - public final ParallelFlowable map(@NonNull Function mapper, @NonNull BiFunction errorHandler) { - Objects.requireNonNull(mapper, "mapper"); + public final <@NonNull R> ParallelFlowable map(@NonNull Function mapper, @NonNull BiFunction errorHandler) { + Objects.requireNonNull(mapper, "mapper is null"); Objects.requireNonNull(errorHandler, "errorHandler is null"); return RxJavaPlugins.onAssembly(new ParallelMapTry<>(this, mapper, errorHandler)); } @@ -259,15 +272,16 @@ public final ParallelFlowable map(@NonNull FunctionScheduler: *
{@code filter} does not operate by default on a particular {@link Scheduler}.
*
- * @param predicate the function returning true to keep a value or false to drop a value - * @return the new ParallelFlowable instance + * @param predicate the function returning {@code true} to keep a value or {@code false} to drop a value + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code predicate} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.PASS_THROUGH) public final ParallelFlowable filter(@NonNull Predicate predicate) { - Objects.requireNonNull(predicate, "predicate"); + Objects.requireNonNull(predicate, "predicate is null"); return RxJavaPlugins.onAssembly(new ParallelFilter<>(this, predicate)); } @@ -284,10 +298,11 @@ public final ParallelFlowable filter(@NonNull Predicate predicate) *
{@code filter} does not operate by default on a particular {@link Scheduler}.
*
*

History: 2.0.8 - experimental - * @param predicate the function returning true to keep a value or false to drop a value + * @param predicate the function returning {@code true} to keep a value or {@code false} to drop a value * @param errorHandler the enumeration that defines how to handle errors thrown - * from the predicate - * @return the new ParallelFlowable instance + * from the {@code predicate} + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code predicate} or {@code errorHandler} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -295,7 +310,7 @@ public final ParallelFlowable filter(@NonNull Predicate predicate) @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.PASS_THROUGH) public final ParallelFlowable filter(@NonNull Predicate predicate, @NonNull ParallelFailureHandling errorHandler) { - Objects.requireNonNull(predicate, "predicate"); + Objects.requireNonNull(predicate, "predicate is null"); Objects.requireNonNull(errorHandler, "errorHandler is null"); return RxJavaPlugins.onAssembly(new ParallelFilterTry<>(this, predicate, errorHandler)); } @@ -313,11 +328,12 @@ public final ParallelFlowable filter(@NonNull Predicate predicate, *

{@code map} does not operate by default on a particular {@link Scheduler}.
* *

History: 2.0.8 - experimental - * @param predicate the function returning true to keep a value or false to drop a value + * @param predicate the function returning {@code true} to keep a value or {@code false} to drop a value * @param errorHandler the function called with the current repeat count and - * failure Throwable and should return one of the {@link ParallelFailureHandling} + * failure {@link Throwable} and should return one of the {@link ParallelFailureHandling} * enumeration values to indicate how to proceed. - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code predicate} or {@code errorHandler} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -325,25 +341,25 @@ public final ParallelFlowable filter(@NonNull Predicate predicate, @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.PASS_THROUGH) public final ParallelFlowable filter(@NonNull Predicate predicate, @NonNull BiFunction errorHandler) { - Objects.requireNonNull(predicate, "predicate"); + Objects.requireNonNull(predicate, "predicate is null"); Objects.requireNonNull(errorHandler, "errorHandler is null"); return RxJavaPlugins.onAssembly(new ParallelFilterTry<>(this, predicate, errorHandler)); } /** - * Specifies where each 'rail' will observe its incoming values with + * Specifies where each 'rail' will observe its incoming values, specified via a {@link Scheduler}, with * no work-stealing and default prefetch amount. *

- * This operator uses the default prefetch size returned by {@code Flowable.bufferSize()}. + * This operator uses the default prefetch size returned by {@link Flowable#bufferSize()}. *

- * The operator will call {@code Scheduler.createWorker()} as many - * times as this ParallelFlowable's parallelism level is. + * The operator will call {@link Scheduler#createWorker()} as many + * times as this {@code ParallelFlowable}'s parallelism level is. *

- * No assumptions are made about the Scheduler's parallelism level, - * if the Scheduler's parallelism level is lower than the ParallelFlowable's, + * No assumptions are made about the {@code Scheduler}'s parallelism level, + * if the {@code Scheduler}'s parallelism level is lower than the {@code ParallelFlowable}'s, * some rails may end up on the same thread/worker. *

- * This operator doesn't require the Scheduler to be trampolining as it + * This operator doesn't require the {@code Scheduler} to be trampolining as it * does its own built-in trampolining logic. *

*
Backpressure:
@@ -351,12 +367,13 @@ public final ParallelFlowable filter(@NonNull Predicate predicate, * requests {@link Flowable#bufferSize} amount from the upstream, followed * by 75% of that amount requested after every 75% received. *
Scheduler:
- *
{@code runOn} drains the upstream rails on the specified {@link Scheduler}'s + *
{@code runOn} drains the upstream rails on the specified {@code Scheduler}'s * {@link io.reactivex.rxjava3.core.Scheduler.Worker Worker}s.
*
* * @param scheduler the scheduler to use - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} */ @CheckReturnValue @NonNull @@ -367,19 +384,19 @@ public final ParallelFlowable runOn(@NonNull Scheduler scheduler) { } /** - * Specifies where each 'rail' will observe its incoming values with + * Specifies where each 'rail' will observe its incoming values, specified via a {@link Scheduler}, with * possibly work-stealing and a given prefetch amount. *

- * This operator uses the default prefetch size returned by {@code Flowable.bufferSize()}. + * This operator uses the default prefetch size returned by {@link Flowable#bufferSize()}. *

- * The operator will call {@code Scheduler.createWorker()} as many - * times as this ParallelFlowable's parallelism level is. + * The operator will call {@link Scheduler#createWorker()} as many + * times as this {@code ParallelFlowable}'s parallelism level is. *

- * No assumptions are made about the Scheduler's parallelism level, - * if the Scheduler's parallelism level is lower than the ParallelFlowable's, + * No assumptions are made about the {@code Scheduler}'s parallelism level, + * if the {@code Scheduler}'s parallelism level is lower than the {@code ParallelFlowable}'s, * some rails may end up on the same thread/worker. *

- * This operator doesn't require the Scheduler to be trampolining as it + * This operator doesn't require the {@code Scheduler} to be trampolining as it * does its own built-in trampolining logic. *

*
Backpressure:
@@ -387,28 +404,30 @@ public final ParallelFlowable runOn(@NonNull Scheduler scheduler) { * requests the {@code prefetch} amount from the upstream, followed * by 75% of that amount requested after every 75% received. *
Scheduler:
- *
{@code runOn} drains the upstream rails on the specified {@link Scheduler}'s + *
{@code runOn} drains the upstream rails on the specified {@code Scheduler}'s * {@link io.reactivex.rxjava3.core.Scheduler.Worker Worker}s.
*
* * @param scheduler the scheduler to use * that rail's worker has run out of work. * @param prefetch the number of values to request on each 'rail' from the source - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.CUSTOM) public final ParallelFlowable runOn(@NonNull Scheduler scheduler, int prefetch) { - Objects.requireNonNull(scheduler, "scheduler"); + Objects.requireNonNull(scheduler, "scheduler is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); return RxJavaPlugins.onAssembly(new ParallelRunOn<>(this, scheduler, prefetch)); } /** - * Reduces all values within a 'rail' and across 'rails' with a reducer function into a single - * sequential value. + * Reduces all values within a 'rail' and across 'rails' with a reducer function into one + * {@link Flowable} sequence. *

* Note that the same reducer function may be called from multiple threads concurrently. *

@@ -419,20 +438,21 @@ public final ParallelFlowable runOn(@NonNull Scheduler scheduler, int prefetc *
{@code reduce} does not operate by default on a particular {@link Scheduler}.
*
* @param reducer the function to reduce two values into one. - * @return the new Flowable instance emitting the reduced value or empty if the ParallelFlowable was empty + * @return the new {@code Flowable} instance emitting the reduced value or empty if the current {@code ParallelFlowable} is empty + * @throws NullPointerException if {@code reducer} is {@code null} */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) public final Flowable reduce(@NonNull BiFunction reducer) { - Objects.requireNonNull(reducer, "reducer"); + Objects.requireNonNull(reducer, "reducer is null"); return RxJavaPlugins.onAssembly(new ParallelReduceFull<>(this, reducer)); } /** * Reduces all values within a 'rail' to a single value (with a possibly different type) via - * a reducer function that is initialized on each rail from an initialSupplier value. + * a reducer function that is initialized on each rail from an {@code initialSupplier} value. *

* Note that the same mapper function may be called from multiple threads concurrently. *

@@ -446,21 +466,22 @@ public final Flowable reduce(@NonNull BiFunction reducer) { * @param initialSupplier the supplier for the initial value * @param reducer the function to reduce a previous output of reduce (or the initial value supplied) * with a current source value. - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code initialSupplier} or {@code reducer} is {@code null} */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) - public final ParallelFlowable reduce(@NonNull Supplier initialSupplier, @NonNull BiFunction reducer) { - Objects.requireNonNull(initialSupplier, "initialSupplier"); - Objects.requireNonNull(reducer, "reducer"); + public final <@NonNull R> ParallelFlowable reduce(@NonNull Supplier initialSupplier, @NonNull BiFunction reducer) { + Objects.requireNonNull(initialSupplier, "initialSupplier is null"); + Objects.requireNonNull(reducer, "reducer is null"); return RxJavaPlugins.onAssembly(new ParallelReduce<>(this, initialSupplier, reducer)); } /** * Merges the values from each 'rail' in a round-robin or same-order fashion and - * exposes it as a regular Publisher sequence, running with a default prefetch value + * exposes it as a regular {@link Flowable} sequence, running with a default prefetch value * for the rails. *

* This operator uses the default prefetch size returned by {@code Flowable.bufferSize()}. @@ -473,7 +494,7 @@ public final ParallelFlowable reduce(@NonNull Supplier initialSupplier *

Scheduler:
*
{@code sequential} does not operate by default on a particular {@link Scheduler}.
*
- * @return the new Flowable instance + * @return the new {@code Flowable} instance * @see ParallelFlowable#sequential(int) * @see ParallelFlowable#sequentialDelayError() */ @@ -487,7 +508,7 @@ public final Flowable sequential() { /** * Merges the values from each 'rail' in a round-robin or same-order fashion and - * exposes it as a regular Publisher sequence, running with a give prefetch value + * exposes it as a regular {@link Flowable} sequence, running with a give prefetch value * for the rails. * *
@@ -499,7 +520,8 @@ public final Flowable sequential() { *
{@code sequential} does not operate by default on a particular {@link Scheduler}.
*
* @param prefetch the prefetch amount to use for each rail - * @return the new Flowable instance + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code prefetch} is non-positive * @see ParallelFlowable#sequential() * @see ParallelFlowable#sequentialDelayError(int) */ @@ -514,7 +536,7 @@ public final Flowable sequential(int prefetch) { /** * Merges the values from each 'rail' in a round-robin or same-order fashion and - * exposes it as a regular Flowable sequence, running with a default prefetch value + * exposes it as a regular {@link Flowable} sequence, running with a default prefetch value * for the rails and delaying errors from all rails till all terminate. *

* This operator uses the default prefetch size returned by {@code Flowable.bufferSize()}. @@ -528,7 +550,7 @@ public final Flowable sequential(int prefetch) { *

{@code sequentialDelayError} does not operate by default on a particular {@link Scheduler}.
* *

History: 2.0.7 - experimental - * @return the new Flowable instance + * @return the new {@code Flowable} instance * @see ParallelFlowable#sequentialDelayError(int) * @see ParallelFlowable#sequential() * @since 2.2 @@ -543,7 +565,7 @@ public final Flowable sequentialDelayError() { /** * Merges the values from each 'rail' in a round-robin or same-order fashion and - * exposes it as a regular Publisher sequence, running with a give prefetch value + * exposes it as a regular {@link Flowable} sequence, running with a give prefetch value * for the rails and delaying errors from all rails till all terminate. * *

@@ -556,7 +578,8 @@ public final Flowable sequentialDelayError() { *
*

History: 2.0.7 - experimental * @param prefetch the prefetch amount to use for each rail - * @return the new Flowable instance + * @return the new {@code Flowable} instance + * @throws IllegalArgumentException if {@code prefetch} is non-positive * @see ParallelFlowable#sequential() * @see ParallelFlowable#sequentialDelayError() * @since 2.2 @@ -571,10 +594,10 @@ public final Flowable sequentialDelayError(int prefetch) { } /** - * Sorts the 'rails' of this ParallelFlowable and returns a Publisher that sequentially + * Sorts the 'rails' of this {@code ParallelFlowable} and returns a {@link Flowable} that sequentially * picks the smallest next value from the rails. *

- * This operator requires a finite source ParallelFlowable. + * This operator requires a finite source {@code ParallelFlowable}. *

*
Backpressure:
*
The operator honors backpressure from the downstream and @@ -584,7 +607,8 @@ public final Flowable sequentialDelayError(int prefetch) { *
* * @param comparator the comparator to use - * @return the new Flowable instance + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code comparator} is {@code null} */ @CheckReturnValue @NonNull @@ -595,10 +619,10 @@ public final Flowable sorted(@NonNull Comparator comparator) { } /** - * Sorts the 'rails' of this ParallelFlowable and returns a Publisher that sequentially + * Sorts the 'rails' of this {@code ParallelFlowable} and returns a {@link Flowable} that sequentially * picks the smallest next value from the rails. *

- * This operator requires a finite source ParallelFlowable. + * This operator requires a finite source {@code ParallelFlowable}. *

*
Backpressure:
*
The operator honors backpressure from the downstream and @@ -609,7 +633,9 @@ public final Flowable sorted(@NonNull Comparator comparator) { * * @param comparator the comparator to use * @param capacityHint the expected number of total elements - * @return the new Flowable instance + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code comparator} is {@code null} + * @throws IllegalArgumentException if {@code capacityHint} is non-positive */ @CheckReturnValue @NonNull @@ -626,9 +652,9 @@ public final Flowable sorted(@NonNull Comparator comparator, int c } /** - * Sorts the 'rails' according to the comparator and returns a full sorted list as a Publisher. + * Sorts the 'rails' according to the comparator and returns a full sorted {@link List} as a {@link Flowable}. *

- * This operator requires a finite source ParallelFlowable. + * This operator requires a finite source {@code ParallelFlowable}. *

*
Backpressure:
*
The operator honors backpressure from the downstream and @@ -638,7 +664,8 @@ public final Flowable sorted(@NonNull Comparator comparator, int c *
* * @param comparator the comparator to compare elements - * @return the new Flowable instance + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code comparator} is {@code null} */ @CheckReturnValue @NonNull @@ -648,9 +675,9 @@ public final Flowable> toSortedList(@NonNull Comparator compa return toSortedList(comparator, 16); } /** - * Sorts the 'rails' according to the comparator and returns a full sorted list as a Publisher. + * Sorts the 'rails' according to the comparator and returns a full sorted {@link List} as a {@link Flowable}. *

- * This operator requires a finite source ParallelFlowable. + * This operator requires a finite source {@code ParallelFlowable}. *

*
Backpressure:
*
The operator honors backpressure from the downstream and @@ -661,7 +688,9 @@ public final Flowable> toSortedList(@NonNull Comparator compa * * @param comparator the comparator to compare elements * @param capacityHint the expected number of total elements - * @return the new Flowable instance + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code comparator} is {@code null} + * @throws IllegalArgumentException if {@code capacityHint} is non-positive */ @CheckReturnValue @NonNull @@ -691,7 +720,8 @@ public final Flowable> toSortedList(@NonNull Comparator compa *
* * @param onNext the callback - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code onNext} is {@code null} */ @CheckReturnValue @NonNull @@ -724,8 +754,9 @@ public final ParallelFlowable doOnNext(@NonNull Consumer onNext) { *

History: 2.0.8 - experimental * @param onNext the callback * @param errorHandler the enumeration that defines how to handle errors thrown - * from the onNext consumer - * @return the new ParallelFlowable instance + * from the {@code onNext} consumer + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code onNext} or {@code errorHandler} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -751,9 +782,10 @@ public final ParallelFlowable doOnNext(@NonNull Consumer onNext, @ *

History: 2.0.8 - experimental * @param onNext the callback * @param errorHandler the function called with the current repeat count and - * failure Throwable and should return one of the {@link ParallelFailureHandling} + * failure {@link Throwable} and should return one of the {@link ParallelFailureHandling} * enumeration values to indicate how to proceed. - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code onNext} or {@code errorHandler} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -778,7 +810,8 @@ public final ParallelFlowable doOnNext(@NonNull Consumer onNext, @ *

* * @param onAfterNext the callback - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code onAfterNext} is {@code null} */ @CheckReturnValue @NonNull @@ -809,13 +842,14 @@ public final ParallelFlowable doAfterNext(@NonNull Consumer onAfte * * * @param onError the callback - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code onError} is {@code null} */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public final ParallelFlowable doOnError(@NonNull Consumer onError) { + public final ParallelFlowable doOnError(@NonNull Consumer onError) { Objects.requireNonNull(onError, "onError is null"); return RxJavaPlugins.onAssembly(new ParallelPeek<>(this, Functions.emptyConsumer(), @@ -830,7 +864,7 @@ public final ParallelFlowable doOnError(@NonNull Consumer onError) } /** - * Run the specified Action when a 'rail' completes. + * Run the specified {@link Action} when a 'rail' completes. *
*
Backpressure:
*
The operator is a pass-through for backpressure and the behavior @@ -840,7 +874,8 @@ public final ParallelFlowable doOnError(@NonNull Consumer onError) *
* * @param onComplete the callback - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code onComplete} is {@code null} */ @CheckReturnValue @NonNull @@ -861,7 +896,7 @@ public final ParallelFlowable doOnComplete(@NonNull Action onComplete) { } /** - * Run the specified Action when a 'rail' completes or signals an error. + * Run the specified {@link Action} when a 'rail' completes or signals an error. *
*
Backpressure:
*
The operator is a pass-through for backpressure and the behavior @@ -871,7 +906,8 @@ public final ParallelFlowable doOnComplete(@NonNull Action onComplete) { *
* * @param onAfterTerminate the callback - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code onAfterTerminate} is {@code null} */ @CheckReturnValue @NonNull @@ -892,7 +928,7 @@ public final ParallelFlowable doAfterTerminated(@NonNull Action onAfterTermin } /** - * Call the specified callback when a 'rail' receives a Subscription from its upstream. + * Call the specified callback when a 'rail' receives a {@link Subscription} from its upstream. *
*
Backpressure:
*
The operator is a pass-through for backpressure and the behavior @@ -902,7 +938,8 @@ public final ParallelFlowable doAfterTerminated(@NonNull Action onAfterTermin *
* * @param onSubscribe the callback - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code onSubscribe} is {@code null} */ @CheckReturnValue @NonNull @@ -933,7 +970,8 @@ public final ParallelFlowable doOnSubscribe(@NonNull Consumer * * @param onRequest the callback - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code onRequest} is {@code null} */ @CheckReturnValue @NonNull @@ -954,7 +992,7 @@ public final ParallelFlowable doOnRequest(@NonNull LongConsumer onRequest) { } /** - * Run the specified Action when a 'rail' receives a cancellation. + * Run the specified {@link Action} when a 'rail' receives a cancellation. *
*
Backpressure:
*
The operator is a pass-through for backpressure and the behavior @@ -964,7 +1002,8 @@ public final ParallelFlowable doOnRequest(@NonNull LongConsumer onRequest) { *
* * @param onCancel the callback - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code onCancel} is {@code null} */ @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) @@ -985,7 +1024,7 @@ public final ParallelFlowable doOnCancel(@NonNull Action onCancel) { } /** - * Collect the elements in each rail into a collection supplied via a collectionSupplier + * Collect the elements in each rail into a collection supplied via a {@code collectionSupplier} * and collected into with a collector action, emitting the collection at the end. *
*
Backpressure:
@@ -998,20 +1037,21 @@ public final ParallelFlowable doOnCancel(@NonNull Action onCancel) { * @param the collection type * @param collectionSupplier the supplier of the collection in each rail * @param collector the collector, taking the per-rail collection and the current item - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code collectionSupplier} or {@code collector} is {@code null} */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) - public final ParallelFlowable collect(@NonNull Supplier collectionSupplier, @NonNull BiConsumer collector) { + public final <@NonNull C> ParallelFlowable collect(@NonNull Supplier collectionSupplier, @NonNull BiConsumer collector) { Objects.requireNonNull(collectionSupplier, "collectionSupplier is null"); Objects.requireNonNull(collector, "collector is null"); return RxJavaPlugins.onAssembly(new ParallelCollect<>(this, collectionSupplier, collector)); } /** - * Wraps multiple Publishers into a ParallelFlowable which runs them + * Wraps multiple {@link Publisher}s into a {@code ParallelFlowable} which runs them * in parallel and unordered. *
*
Backpressure:
@@ -1023,7 +1063,9 @@ public final ParallelFlowable collect(@NonNull Supplier coll * * @param the value type * @param publishers the array of publishers - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code publishers} is {@code null} + * @throws IllegalArgumentException if {@code publishers} is an empty array */ @CheckReturnValue @NonNull @@ -1031,6 +1073,7 @@ public final ParallelFlowable collect(@NonNull Supplier coll @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) public static <@NonNull T> ParallelFlowable fromArray(@NonNull Publisher... publishers) { + Objects.requireNonNull(publishers, "publishers is null"); if (publishers.length == 0) { throw new IllegalArgumentException("Zero publishers not supported"); } @@ -1050,9 +1093,9 @@ public final ParallelFlowable collect(@NonNull Supplier coll *
*

History: 2.1.7 - experimental * @param the resulting object type - * @param converter the function that receives the current ParallelFlowable instance and returns a value + * @param converter the function that receives the current {@code ParallelFlowable} instance and returns a value * @return the converted value - * @throws NullPointerException if converter is null + * @throws NullPointerException if {@code converter} is {@code null} * @since 2.2 */ @CheckReturnValue @@ -1064,8 +1107,8 @@ public final ParallelFlowable collect(@NonNull Supplier coll } /** - * Allows composing operators, in assembly time, on top of this ParallelFlowable - * and returns another ParallelFlowable with composed features. + * Allows composing operators, in assembly time, on top of this {@code ParallelFlowable} + * and returns another {@code ParallelFlowable} with composed features. *

*
Backpressure:
*
The operator is a pass-through for backpressure and the behavior @@ -1075,46 +1118,48 @@ public final ParallelFlowable collect(@NonNull Supplier coll *
* * @param the output value type - * @param composer the composer function from ParallelFlowable (this) to another ParallelFlowable - * @return the ParallelFlowable returned by the function + * @param composer the composer function from {@code ParallelFlowable} (this) to another {@code ParallelFlowable} + * @return the {@code ParallelFlowable} returned by the function + * @throws NullPointerException if {@code composer} is {@code null} */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public final ParallelFlowable compose(@NonNull ParallelTransformer composer) { + public final <@NonNull U> ParallelFlowable compose(@NonNull ParallelTransformer composer) { return RxJavaPlugins.onAssembly(Objects.requireNonNull(composer, "composer is null").apply(this)); } /** - * Generates and flattens Publishers on each 'rail'. + * Generates and flattens {@link Publisher}s on each 'rail'. *

- * Errors are not delayed and uses unbounded concurrency along with default inner prefetch. + * The errors are not delayed and uses unbounded concurrency along with default inner prefetch. *

*
Backpressure:
*
The operator honors backpressure from the downstream rails and * requests {@link Flowable#bufferSize()} amount from each rail upfront * and keeps requesting as many items per rail as many inner sources on * that rail completed. The inner sources are requested {@link Flowable#bufferSize()} - * amount upfront, then 75% of this amount requested after 75% received. + * amount upfront, then 75% of this amount requested after 75% received.
*
Scheduler:
*
{@code flatMap} does not operate by default on a particular {@link Scheduler}.
*
* * @param the result type - * @param mapper the function to map each rail's value into a Publisher - * @return the new ParallelFlowable instance + * @param mapper the function to map each rail's value into a {@code Publisher} + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final ParallelFlowable flatMap(@NonNull Function> mapper) { + public final <@NonNull R> ParallelFlowable flatMap(@NonNull Function> mapper) { return flatMap(mapper, false, Flowable.bufferSize(), Flowable.bufferSize()); } /** - * Generates and flattens Publishers on each 'rail', optionally delaying errors. + * Generates and flattens {@link Publisher}s on each 'rail', optionally delaying errors. *

* It uses unbounded concurrency along with default inner prefetch. *

@@ -1130,22 +1175,23 @@ public final ParallelFlowable flatMap(@NonNull Function * * @param the result type - * @param mapper the function to map each rail's value into a Publisher + * @param mapper the function to map each rail's value into a {@code Publisher} * @param delayError should the errors from the main and the inner sources delayed till everybody terminates? - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final ParallelFlowable flatMap( - @NonNull Function> mapper, boolean delayError) { + public final <@NonNull R> ParallelFlowable flatMap( + @NonNull Function> mapper, boolean delayError) { return flatMap(mapper, delayError, Flowable.bufferSize(), Flowable.bufferSize()); } /** - * Generates and flattens Publishers on each 'rail', optionally delaying errors - * and having a total number of simultaneous subscriptions to the inner Publishers. + * Generates and flattens {@link Publisher}s on each 'rail', optionally delaying errors + * and having a total number of simultaneous subscriptions to the inner {@code Publisher}s. *

* It uses a default inner prefetch. *

@@ -1161,24 +1207,26 @@ public final ParallelFlowable flatMap( *
* * @param the result type - * @param mapper the function to map each rail's value into a Publisher + * @param mapper the function to map each rail's value into a {@code Publisher} * @param delayError should the errors from the main and the inner sources delayed till everybody terminates? - * @param maxConcurrency the maximum number of simultaneous subscriptions to the generated inner Publishers - * @return the new ParallelFlowable instance + * @param maxConcurrency the maximum number of simultaneous subscriptions to the generated inner {@code Publisher}s + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final ParallelFlowable flatMap( - @NonNull Function> mapper, boolean delayError, int maxConcurrency) { + public final <@NonNull R> ParallelFlowable flatMap( + @NonNull Function> mapper, boolean delayError, int maxConcurrency) { return flatMap(mapper, delayError, maxConcurrency, Flowable.bufferSize()); } /** - * Generates and flattens Publishers on each 'rail', optionally delaying errors, - * having a total number of simultaneous subscriptions to the inner Publishers - * and using the given prefetch amount for the inner Publishers. + * Generates and flattens {@link Publisher}s on each 'rail', optionally delaying errors, + * having a total number of simultaneous subscriptions to the inner {@code Publisher}s + * and using the given prefetch amount for the inner {@code Publisher}s. *
*
Backpressure:
*
The operator honors backpressure from the downstream rails and @@ -1192,18 +1240,20 @@ public final ParallelFlowable flatMap( *
* * @param the result type - * @param mapper the function to map each rail's value into a Publisher + * @param mapper the function to map each rail's value into a {@code Publisher} * @param delayError should the errors from the main and the inner sources delayed till everybody terminates? - * @param maxConcurrency the maximum number of simultaneous subscriptions to the generated inner Publishers - * @param prefetch the number of items to prefetch from each inner Publisher - * @return the new ParallelFlowable instance + * @param maxConcurrency the maximum number of simultaneous subscriptions to the generated inner {@code Publisher}s + * @param prefetch the number of items to prefetch from each inner {@code Publisher} + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code maxConcurrency} or {@code prefetch} is non-positive */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final ParallelFlowable flatMap( - @NonNull Function> mapper, + public final <@NonNull R> ParallelFlowable flatMap( + @NonNull Function> mapper, boolean delayError, int maxConcurrency, int prefetch) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); @@ -1212,7 +1262,7 @@ public final ParallelFlowable flatMap( } /** - * Generates and concatenates Publishers on each 'rail', signalling errors immediately + * Generates and concatenates {@link Publisher}s on each 'rail', signalling errors immediately * and generating 2 publishers upfront. *
*
Backpressure:
@@ -1225,22 +1275,23 @@ public final ParallelFlowable flatMap( *
* * @param the result type - * @param mapper the function to map each rail's value into a Publisher - * source and the inner Publishers (immediate, boundary, end) - * @return the new ParallelFlowable instance + * @param mapper the function to map each rail's value into a {@code Publisher} + * source and the inner {@code Publisher}s (immediate, boundary, end) + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final ParallelFlowable concatMap( - @NonNull Function> mapper) { + public final <@NonNull R> ParallelFlowable concatMap( + @NonNull Function> mapper) { return concatMap(mapper, 2); } /** - * Generates and concatenates Publishers on each 'rail', signalling errors immediately - * and using the given prefetch amount for generating Publishers upfront. + * Generates and concatenates {@link Publisher}s on each 'rail', signalling errors immediately + * and using the given prefetch amount for generating {@code Publisher}s upfront. *
*
Backpressure:
*
The operator honors backpressure from the downstream rails and @@ -1253,17 +1304,19 @@ public final ParallelFlowable concatMap( *
* * @param the result type - * @param mapper the function to map each rail's value into a Publisher - * @param prefetch the number of items to prefetch from each inner Publisher - * source and the inner Publishers (immediate, boundary, end) - * @return the new ParallelFlowable instance + * @param mapper the function to map each rail's value into a {@code Publisher} + * @param prefetch the number of items to prefetch from each inner {@code Publisher} + * source and the inner {@code Publisher}s (immediate, boundary, end) + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final ParallelFlowable concatMap( - @NonNull Function> mapper, + public final <@NonNull R> ParallelFlowable concatMap( + @NonNull Function> mapper, int prefetch) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); @@ -1271,7 +1324,7 @@ public final ParallelFlowable concatMap( } /** - * Generates and concatenates Publishers on each 'rail', optionally delaying errors + * Generates and concatenates {@link Publisher}s on each 'rail', optionally delaying errors * and generating 2 publishers upfront. *
*
Backpressure:
@@ -1284,25 +1337,26 @@ public final ParallelFlowable concatMap( *
* * @param the result type - * @param mapper the function to map each rail's value into a Publisher - * @param tillTheEnd if true all errors from the upstream and inner Publishers are delayed - * till all of them terminate, if false, the error is emitted when an inner Publisher terminates. - * source and the inner Publishers (immediate, boundary, end) - * @return the new ParallelFlowable instance + * @param mapper the function to map each rail's value into a {@code Publisher} + * @param tillTheEnd if {@code true}, all errors from the upstream and inner {@code Publisher}s are delayed + * till all of them terminate, if {@code false}, the error is emitted when an inner {@code Publisher} terminates. + * source and the inner {@code Publisher}s (immediate, boundary, end) + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final ParallelFlowable concatMapDelayError( - @NonNull Function> mapper, + public final <@NonNull R> ParallelFlowable concatMapDelayError( + @NonNull Function> mapper, boolean tillTheEnd) { return concatMapDelayError(mapper, 2, tillTheEnd); } /** - * Generates and concatenates Publishers on each 'rail', optionally delaying errors - * and using the given prefetch amount for generating Publishers upfront. + * Generates and concatenates {@link Publisher}s on each 'rail', optionally delaying errors + * and using the given prefetch amount for generating {@code Publisher}s upfront. *
*
Backpressure:
*
The operator honors backpressure from the downstream rails and @@ -1315,18 +1369,20 @@ public final ParallelFlowable concatMapDelayError( *
* * @param the result type - * @param mapper the function to map each rail's value into a Publisher - * @param prefetch the number of items to prefetch from each inner Publisher - * @param tillTheEnd if true all errors from the upstream and inner Publishers are delayed - * till all of them terminate, if false, the error is emitted when an inner Publisher terminates. - * @return the new ParallelFlowable instance + * @param mapper the function to map each rail's value into a {@code Publisher} + * @param prefetch the number of items to prefetch from each inner {@code Publisher} + * @param tillTheEnd if {@code true}, all errors from the upstream and inner {@code Publisher}s are delayed + * till all of them terminate, if {@code false}, the error is emitted when an inner {@code Publisher} terminates. + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final ParallelFlowable concatMapDelayError( - @NonNull Function> mapper, + public final <@NonNull R> ParallelFlowable concatMapDelayError( + @NonNull Function> mapper, int prefetch, boolean tillTheEnd) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); @@ -1338,12 +1394,12 @@ public final ParallelFlowable concatMapDelayError( * Returns a {@code ParallelFlowable} that merges each item emitted by the source on each rail with the values in an * {@link Iterable} corresponding to that item that is generated by a selector. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from each downstream rail. The source {@code ParallelFlowable}s is * expected to honor backpressure as well. If the source {@code ParallelFlowable} violates the rule, the operator will - * signal a {@code MissingBackpressureException}.
+ * signal a {@link MissingBackpressureException}. *
Scheduler:
*
{@code flatMapIterable} does not operate by default on a particular {@link Scheduler}.
*
@@ -1353,29 +1409,30 @@ public final ParallelFlowable concatMapDelayError( * @param mapper * a function that returns an {@code Iterable} sequence of values for when given an item emitted by the * source {@code ParallelFlowable} - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance * @see ReactiveX operators documentation: FlatMap * @see #flatMapStream(Function) * @since 3.0.0 + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final ParallelFlowable flatMapIterable(@NonNull Function> mapper) { + public final <@NonNull U> ParallelFlowable flatMapIterable(@NonNull Function> mapper) { return flatMapIterable(mapper, Flowable.bufferSize()); } /** * Returns a {@code ParallelFlowable} that merges each item emitted by the source {@code ParallelFlowable} with the values in an - * Iterable corresponding to that item that is generated by a selector. + * {@link Iterable} corresponding to that item that is generated by a selector. *

- * + * *

*
Backpressure:
*
The operator honors backpressure from each downstream rail. The source {@code ParallelFlowable}s is * expected to honor backpressure as well. If the source {@code ParallelFlowable} violates the rule, the operator will - * signal a {@code MissingBackpressureException}.
+ * signal a {@link MissingBackpressureException}. *
Scheduler:
*
{@code flatMapIterable} does not operate by default on a particular {@link Scheduler}.
*
@@ -1391,12 +1448,14 @@ public final ParallelFlowable flatMapIterable(@NonNull FunctionReactiveX operators documentation: FlatMap * @see #flatMapStream(Function, int) * @since 3.0.0 + * @throws NullPointerException if {@code mapper} is {@code null} + * @throws IllegalArgumentException if {@code bufferSize} is non-positive */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public final ParallelFlowable flatMapIterable(@NonNull Function> mapper, int bufferSize) { + public final <@NonNull U> ParallelFlowable flatMapIterable(@NonNull Function> mapper, int bufferSize) { Objects.requireNonNull(mapper, "mapper is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); return RxJavaPlugins.onAssembly(new ParallelFlatMapIterable<>(this, mapper, bufferSize)); @@ -1419,15 +1478,16 @@ public final ParallelFlowable flatMapIterable(@NonNull Function * @param the output value type * @param mapper the mapper function turning Ts into optional of Rs. - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance * @since 3.0.0 + * @throws NullPointerException if {@code mapper} is {@code null} */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.PASS_THROUGH) - public final ParallelFlowable mapOptional(@NonNull Function> mapper) { - Objects.requireNonNull(mapper, "mapper"); + public final <@NonNull R> ParallelFlowable mapOptional(@NonNull Function> mapper) { + Objects.requireNonNull(mapper, "mapper is null"); return RxJavaPlugins.onAssembly(new ParallelMapOptional<>(this, mapper)); } @@ -1448,15 +1508,16 @@ public final ParallelFlowable mapOptional(@NonNull Function ParallelFlowable mapOptional(@NonNull Function> mapper, @NonNull ParallelFailureHandling errorHandler) { - Objects.requireNonNull(mapper, "mapper"); + public final <@NonNull R> ParallelFlowable mapOptional(@NonNull Function> mapper, @NonNull ParallelFailureHandling errorHandler) { + Objects.requireNonNull(mapper, "mapper is null"); Objects.requireNonNull(errorHandler, "errorHandler is null"); return RxJavaPlugins.onAssembly(new ParallelMapTryOptional<>(this, mapper, errorHandler)); } @@ -1477,17 +1538,18 @@ public final ParallelFlowable mapOptional(@NonNull Function the output value type * @param mapper the mapper function turning Ts into optional of Rs. * @param errorHandler the function called with the current repeat count and - * failure Throwable and should return one of the {@link ParallelFailureHandling} + * failure {@link Throwable} and should return one of the {@link ParallelFailureHandling} * enumeration values to indicate how to proceed. - * @return the new ParallelFlowable instance + * @return the new {@code ParallelFlowable} instance + * @throws NullPointerException if {@code mapper} or {@code errorHandler} is {@code null} * @since 3.0.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.PASS_THROUGH) - public final ParallelFlowable mapOptional(@NonNull Function> mapper, @NonNull BiFunction errorHandler) { - Objects.requireNonNull(mapper, "mapper"); + public final <@NonNull R> ParallelFlowable mapOptional(@NonNull Function> mapper, @NonNull BiFunction errorHandler) { + Objects.requireNonNull(mapper, "mapper is null"); Objects.requireNonNull(errorHandler, "errorHandler is null"); return RxJavaPlugins.onAssembly(new ParallelMapTryOptional<>(this, mapper, errorHandler)); } @@ -1497,11 +1559,11 @@ public final ParallelFlowable mapOptional(@NonNull Function * *

- * Due to the blocking and sequential nature of Java {@link Stream}s, the streams are mapped and consumed in a sequential fashion + * Due to the blocking and sequential nature of Java {@code Stream}s, the streams are mapped and consumed in a sequential fashion * without interleaving (unlike a more general {@link #flatMap(Function)}). Therefore, {@code flatMapStream} and * {@code concatMapStream} are identical operators and are provided as aliases. *

- * The operator closes the {@code Stream} upon cancellation and when it terminates. Exceptions raised when + * The operator closes the {@code Stream} upon cancellation and when it terminates. The exceptions raised when * closing a {@code Stream} are routed to the global error handler ({@link RxJavaPlugins#onError(Throwable)}. * If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #flatMapIterable(Function)}: *


@@ -1531,7 +1593,8 @@ public final  ParallelFlowable mapOptional(@NonNull Function the element type of the {@code Stream}s and the result
      * @param mapper the function that receives an upstream item and should return a {@code Stream} whose elements
      * will be emitted to the downstream
-     * @return the new Flowable instance
+     * @return the new {@code ParallelFlowable} instance
+     * @throws NullPointerException if {@code mapper} is {@code null}
      * @see #flatMap(Function)
      * @see #flatMapIterable(Function)
      * @see #flatMapStream(Function, int)
@@ -1550,11 +1613,11 @@ public final  ParallelFlowable mapOptional(@NonNull Function
      * 
      * 

- * Due to the blocking and sequential nature of Java {@link Stream}s, the streams are mapped and consumed in a sequential fashion + * Due to the blocking and sequential nature of Java {@code Stream}s, the streams are mapped and consumed in a sequential fashion * without interleaving (unlike a more general {@link #flatMap(Function)}). Therefore, {@code flatMapStream} and * {@code concatMapStream} are identical operators and are provided as aliases. *

- * The operator closes the {@code Stream} upon cancellation and when it terminates. Exceptions raised when + * The operator closes the {@code Stream} upon cancellation and when it terminates. The exceptions raised when * closing a {@code Stream} are routed to the global error handler ({@link RxJavaPlugins#onError(Throwable)}. * If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #flatMapIterable(Function, int)}: *


@@ -1584,7 +1647,9 @@ public final  ParallelFlowable mapOptional(@NonNull Function ParallelFlowable mapOptional(@NonNull Function
      * Each parallel rail receives its own {@link Collector#accumulator()} and
      * {@link Collector#combiner()}.
@@ -1615,14 +1680,15 @@ public final  ParallelFlowable mapOptional(@NonNull Function the accumulator type
      * @param  the output value type
      * @param collector the {@code Collector} instance
-     * @return the new Flowable instance emitting the collected value.
+     * @return the new {@code Flowable} instance emitting the collected value.
+     * @throws NullPointerException if {@code collector} is {@code null}
      * @since 3.0.0
      */
     @CheckReturnValue
     @NonNull
     @BackpressureSupport(BackpressureKind.UNBOUNDED_IN)
     @SchedulerSupport(SchedulerSupport.NONE)
-    public final  Flowable collect(@NonNull Collector collector) {
+    public final <@NonNull A, @NonNull R> Flowable collect(@NonNull Collector collector) {
         Objects.requireNonNull(collector, "collector is null");
         return RxJavaPlugins.onAssembly(new ParallelCollector<>(this, collector));
     }
diff --git a/src/main/java/io/reactivex/rxjava3/parallel/ParallelFlowableConverter.java b/src/main/java/io/reactivex/rxjava3/parallel/ParallelFlowableConverter.java
index 7033261e65a..47510faf37b 100644
--- a/src/main/java/io/reactivex/rxjava3/parallel/ParallelFlowableConverter.java
+++ b/src/main/java/io/reactivex/rxjava3/parallel/ParallelFlowableConverter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
diff --git a/src/main/java/io/reactivex/rxjava3/parallel/ParallelTransformer.java b/src/main/java/io/reactivex/rxjava3/parallel/ParallelTransformer.java
index 7e6a7734d00..f35f71567c1 100644
--- a/src/main/java/io/reactivex/rxjava3/parallel/ParallelTransformer.java
+++ b/src/main/java/io/reactivex/rxjava3/parallel/ParallelTransformer.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -23,7 +23,7 @@
  * @since 2.2
  */
 @FunctionalInterface
-public interface ParallelTransformer {
+public interface ParallelTransformer<@NonNull Upstream, @NonNull Downstream> {
     /**
      * Applies a function to the upstream ParallelFlowable and returns a ParallelFlowable with
      * optionally different element type.
@@ -32,4 +32,4 @@ public interface ParallelTransformer {
      */
     @NonNull
     ParallelFlowable apply(@NonNull ParallelFlowable upstream);
-}
\ No newline at end of file
+}
diff --git a/src/main/java/io/reactivex/rxjava3/parallel/package-info.java b/src/main/java/io/reactivex/rxjava3/parallel/package-info.java
index 7c9cc785ad4..09605021f07 100644
--- a/src/main/java/io/reactivex/rxjava3/parallel/package-info.java
+++ b/src/main/java/io/reactivex/rxjava3/parallel/package-info.java
@@ -1,21 +1,18 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
  *
  * http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License.
  */
 
 /**
  * Contains the base type {@link io.reactivex.rxjava3.parallel.ParallelFlowable},
  * a sub-DSL for working with {@link io.reactivex.rxjava3.core.Flowable} sequences in parallel.
  */
-package io.reactivex.rxjava3.parallel;
\ No newline at end of file
+package io.reactivex.rxjava3.parallel;
diff --git a/src/main/java/io/reactivex/rxjava3/plugins/RxJavaPlugins.java b/src/main/java/io/reactivex/rxjava3/plugins/RxJavaPlugins.java
index 9012e36f128..2949253b31c 100644
--- a/src/main/java/io/reactivex/rxjava3/plugins/RxJavaPlugins.java
+++ b/src/main/java/io/reactivex/rxjava3/plugins/RxJavaPlugins.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016-present, RxJava Contributors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
@@ -10,11 +10,12 @@
  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
  * the License for the specific language governing permissions and limitations under the License.
  */
+
 package io.reactivex.rxjava3.plugins;
 
 import java.lang.Thread.UncaughtExceptionHandler;
 import java.util.Objects;
-import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.*;
 
 import org.reactivestreams.Subscriber;
 
@@ -95,22 +96,26 @@ public final class RxJavaPlugins {
 
     @SuppressWarnings("rawtypes")
     @Nullable
-    static volatile BiFunction onFlowableSubscribe;
+    static volatile BiFunction onFlowableSubscribe;
 
     @SuppressWarnings("rawtypes")
     @Nullable
-    static volatile BiFunction onMaybeSubscribe;
+    static volatile BiFunction onMaybeSubscribe;
 
     @SuppressWarnings("rawtypes")
     @Nullable
-    static volatile BiFunction onObservableSubscribe;
+    static volatile BiFunction onObservableSubscribe;
 
     @SuppressWarnings("rawtypes")
     @Nullable
-    static volatile BiFunction onSingleSubscribe;
+    static volatile BiFunction onSingleSubscribe;
+
+    @Nullable
+    static volatile BiFunction onCompletableSubscribe;
 
+    @SuppressWarnings("rawtypes")
     @Nullable
-    static volatile BiFunction onCompletableSubscribe;
+    static volatile BiFunction onParallelSubscribe;
 
     @Nullable
     static volatile BooleanSupplier onBeforeBlocking;
@@ -397,10 +402,13 @@ static boolean isBug(Throwable error) {
             return true;
         }
         // the sender didn't honor the request amount
-        // it's either due to an operator bug or concurrent onNext
         if (error instanceof MissingBackpressureException) {
             return true;
         }
+        // it's either due to an operator bug or concurrent onNext
+        if (error instanceof QueueOverflowException) {
+            return true;
+        }
         // general protocol violations
         // it's either due to an operator bug or concurrent onNext
         if (error instanceof IllegalStateException) {
@@ -525,6 +533,7 @@ public static void reset() {
         setOnMaybeSubscribe(null);
 
         setOnParallelAssembly(null);
+        setOnParallelSubscribe(null);
 
         setFailOnNonBlockingScheduler(false);
         setOnBeforeBlocking(null);
@@ -661,7 +670,7 @@ public static void setSingleSchedulerHandler(@Nullable Function getOnCompletableSubscribe() {
+    public static BiFunction getOnCompletableSubscribe() {
         return onCompletableSubscribe;
     }
 
@@ -691,7 +700,7 @@ public static void setSingleSchedulerHandler(@Nullable Function getOnFlowableSubscribe() {
+    public static BiFunction getOnFlowableSubscribe() {
         return onFlowableSubscribe;
     }
 
@@ -701,7 +710,7 @@ public static void setSingleSchedulerHandler(@Nullable Function getOnMaybeSubscribe() {
+    public static BiFunction getOnMaybeSubscribe() {
         return onMaybeSubscribe;
     }
 
@@ -731,7 +740,7 @@ public static void setSingleSchedulerHandler(@Nullable Function getOnSingleSubscribe() {
+    public static BiFunction getOnSingleSubscribe() {
         return onSingleSubscribe;
     }
 
@@ -761,7 +770,7 @@ public static void setSingleSchedulerHandler(@Nullable Function getOnObservableSubscribe() {
+    public static BiFunction getOnObservableSubscribe() {
         return onObservableSubscribe;
     }
 
@@ -781,7 +790,7 @@ public static void setOnCompletableAssembly(@Nullable Function onCompletableSubscribe) {
+            @Nullable BiFunction onCompletableSubscribe) {
         if (lockdown) {
             throw new IllegalStateException("Plugins can't be changed anymore");
         }
@@ -829,7 +838,7 @@ public static void setOnConnectableFlowableAssembly(@Nullable Function onFlowableSubscribe) {
+    public static void setOnFlowableSubscribe(@Nullable BiFunction onFlowableSubscribe) {
         if (lockdown) {
             throw new IllegalStateException("Plugins can't be changed anymore");
         }
@@ -841,7 +850,7 @@ public static void setOnFlowableSubscribe(@Nullable BiFunction onMaybeSubscribe) {
+    public static void setOnMaybeSubscribe(@Nullable BiFunction onMaybeSubscribe) {
         if (lockdown) {
             throw new IllegalStateException("Plugins can't be changed anymore");
         }
@@ -878,7 +887,7 @@ public static void setOnConnectableObservableAssembly(@Nullable Function onObservableSubscribe) {
+            @Nullable BiFunction onObservableSubscribe) {
         if (lockdown) {
             throw new IllegalStateException("Plugins can't be changed anymore");
         }
@@ -902,7 +911,7 @@ public static void setOnSingleAssembly(@Nullable Function onSingleSubscribe) {
+    public static void setOnSingleSubscribe(@Nullable BiFunction onSingleSubscribe) {
         if (lockdown) {
             throw new IllegalStateException("Plugins can't be changed anymore");
         }
@@ -918,8 +927,8 @@ public static void setOnSingleSubscribe(@Nullable BiFunction Subscriber onSubscribe(@NonNull Flowable source, @NonNull Subscriber subscriber) {
-        BiFunction f = onFlowableSubscribe;
+    public static <@NonNull T> Subscriber onSubscribe(@NonNull Flowable source, @NonNull Subscriber subscriber) {
+        BiFunction f = onFlowableSubscribe;
         if (f != null) {
             return apply(f, source, subscriber);
         }
@@ -935,8 +944,8 @@ public static  Subscriber onSubscribe(@NonNull Flowable source,
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @NonNull
-    public static  Observer onSubscribe(@NonNull Observable source, @NonNull Observer observer) {
-        BiFunction f = onObservableSubscribe;
+    public static <@NonNull T> Observer onSubscribe(@NonNull Observable source, @NonNull Observer observer) {
+        BiFunction f = onObservableSubscribe;
         if (f != null) {
             return apply(f, source, observer);
         }
@@ -952,8 +961,8 @@ public static  Observer onSubscribe(@NonNull Observable source,
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @NonNull
-    public static  SingleObserver onSubscribe(@NonNull Single source, @NonNull SingleObserver observer) {
-        BiFunction f = onSingleSubscribe;
+    public static <@NonNull T> SingleObserver onSubscribe(@NonNull Single source, @NonNull SingleObserver observer) {
+        BiFunction f = onSingleSubscribe;
         if (f != null) {
             return apply(f, source, observer);
         }
@@ -968,7 +977,7 @@ public static  SingleObserver onSubscribe(@NonNull Single sourc
      */
     @NonNull
     public static CompletableObserver onSubscribe(@NonNull Completable source, @NonNull CompletableObserver observer) {
-        BiFunction f = onCompletableSubscribe;
+        BiFunction f = onCompletableSubscribe;
         if (f != null) {
             return apply(f, source, observer);
         }
@@ -984,14 +993,31 @@ public static CompletableObserver onSubscribe(@NonNull Completable source, @NonN
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @NonNull
-    public static  MaybeObserver onSubscribe(@NonNull Maybe source, @NonNull MaybeObserver observer) {
-        BiFunction f = onMaybeSubscribe;
+    public static <@NonNull T> MaybeObserver onSubscribe(@NonNull Maybe source, @NonNull MaybeObserver observer) {
+        BiFunction f = onMaybeSubscribe;
         if (f != null) {
             return apply(f, source, observer);
         }
         return observer;
     }
 
+    /**
+     * Calls the associated hook function.
+     * @param  the value type
+     * @param source the hook's input value
+     * @param subscribers the array of subscribers
+     * @return the value returned by the hook
+     */
+    @SuppressWarnings({ "rawtypes" })
+    @NonNull
+    public static <@NonNull T> Subscriber[] onSubscribe(@NonNull ParallelFlowable source, @NonNull Subscriber[] subscribers) {
+        BiFunction f = onParallelSubscribe;
+        if (f != null) {
+            return apply(f, source, subscribers);
+        }
+        return subscribers;
+    }
+
     /**
      * Calls the associated hook function.
      * @param  the value type
@@ -1000,7 +1026,7 @@ public static  MaybeObserver onSubscribe(@NonNull Maybe source,
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @NonNull
-    public static  Maybe onAssembly(@NonNull Maybe source) {
+    public static <@NonNull T> Maybe onAssembly(@NonNull Maybe source) {
         Function f = onMaybeAssembly;
         if (f != null) {
             return apply(f, source);
@@ -1016,7 +1042,7 @@ public static  Maybe onAssembly(@NonNull Maybe source) {
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @NonNull
-    public static  Flowable onAssembly(@NonNull Flowable source) {
+    public static <@NonNull T> Flowable onAssembly(@NonNull Flowable source) {
         Function f = onFlowableAssembly;
         if (f != null) {
             return apply(f, source);
@@ -1032,7 +1058,7 @@ public static  Flowable onAssembly(@NonNull Flowable source) {
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @NonNull
-    public static  ConnectableFlowable onAssembly(@NonNull ConnectableFlowable source) {
+    public static <@NonNull T> ConnectableFlowable onAssembly(@NonNull ConnectableFlowable source) {
         Function f = onConnectableFlowableAssembly;
         if (f != null) {
             return apply(f, source);
@@ -1048,7 +1074,7 @@ public static  ConnectableFlowable onAssembly(@NonNull ConnectableFlowable
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @NonNull
-    public static  Observable onAssembly(@NonNull Observable source) {
+    public static <@NonNull T> Observable onAssembly(@NonNull Observable source) {
         Function f = onObservableAssembly;
         if (f != null) {
             return apply(f, source);
@@ -1064,7 +1090,7 @@ public static  Observable onAssembly(@NonNull Observable source) {
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @NonNull
-    public static  ConnectableObservable onAssembly(@NonNull ConnectableObservable source) {
+    public static <@NonNull T> ConnectableObservable onAssembly(@NonNull ConnectableObservable source) {
         Function f = onConnectableObservableAssembly;
         if (f != null) {
             return apply(f, source);
@@ -1080,7 +1106,7 @@ public static  ConnectableObservable onAssembly(@NonNull ConnectableObserv
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @NonNull
-    public static  Single onAssembly(@NonNull Single source) {
+    public static <@NonNull T> Single onAssembly(@NonNull Single source) {
         Function f = onSingleAssembly;
         if (f != null) {
             return apply(f, source);
@@ -1128,6 +1154,32 @@ public static void setOnParallelAssembly(@Nullable FunctionHistory: 3.0.11 - experimental
+     * @param handler the hook function to set, null allowed
+     * @since 3.1.0
+     */
+    @SuppressWarnings("rawtypes")
+    public static void setOnParallelSubscribe(@Nullable BiFunction handler) {
+        if (lockdown) {
+            throw new IllegalStateException("Plugins can't be changed anymore");
+        }
+        onParallelSubscribe = handler;
+    }
+
+    /**
+     * Returns the current hook function.
+     * 

History: 3.0.11 - experimental + * @return the hook function, may be null + * @since 3.1.0 + */ + @SuppressWarnings("rawtypes") + @Nullable + public static BiFunction getOnParallelSubscribe() { + return onParallelSubscribe; + } + /** * Calls the associated hook function. *

History: 2.0.6 - experimental; 2.1 - beta @@ -1138,7 +1190,7 @@ public static void setOnParallelAssembly(@Nullable Function ParallelFlowable onAssembly(@NonNull ParallelFlowable source) { + public static <@NonNull T> ParallelFlowable onAssembly(@NonNull ParallelFlowable source) { Function f = onParallelAssembly; if (f != null) { return apply(f, source); @@ -1253,6 +1305,26 @@ public static Scheduler createSingleScheduler(@NonNull ThreadFactory threadFacto return new SingleScheduler(Objects.requireNonNull(threadFactory, "threadFactory is null")); } + /** + * Create an instance of a {@link Scheduler} by wrapping an existing {@link Executor}. + *

+ * This method allows creating an {@code Executor}-backed {@code Scheduler} before the {@link Schedulers} class + * would initialize the standard {@code Scheduler}s. + * + * @param executor the {@code Executor} to wrap and turn into a {@code Scheduler}. + * @param interruptibleWorker if {@code true}, the tasks submitted to the {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} will + * be interrupted when the task is disposed. + * @param fair if {@code true}, tasks submitted to the {@code Scheduler} or {@code Worker} will be executed by the underlying {@code Executor} one after the other, still + * in a FIFO and non-overlapping manner, but allows interleaving with other tasks submitted to the underlying {@code Executor}. + * If {@code false}, the underlying FIFO scheme will execute as many tasks as it can before giving up the underlying {@code Executor} thread. + * @return the new {@code Scheduler} wrapping the {@code Executor} + * @since 3.1.0 + */ + @NonNull + public static Scheduler createExecutorScheduler(@NonNull Executor executor, boolean interruptibleWorker, boolean fair) { + return new ExecutorScheduler(executor, interruptibleWorker, fair); + } + /** * Wraps the call to the function in try-catch and propagates thrown * checked exceptions as RuntimeException. @@ -1263,7 +1335,7 @@ public static Scheduler createSingleScheduler(@NonNull ThreadFactory threadFacto * @return the result of the function call */ @NonNull - static R apply(@NonNull Function f, @NonNull T t) { + static <@NonNull T, @NonNull R> R apply(@NonNull Function f, @NonNull T t) { try { return f.apply(t); } catch (Throwable ex) { @@ -1283,7 +1355,7 @@ static R apply(@NonNull Function f, @NonNull T t) { * @return the result of the function call */ @NonNull - static R apply(@NonNull BiFunction f, @NonNull T t, @NonNull U u) { + static <@NonNull T, @NonNull U, @NonNull R> R apply(@NonNull BiFunction f, @NonNull T t, @NonNull U u) { try { return f.apply(t, u); } catch (Throwable ex) { diff --git a/src/main/java/io/reactivex/rxjava3/plugins/package-info.java b/src/main/java/io/reactivex/rxjava3/plugins/package-info.java index a3105506a4f..49390584dff 100644 --- a/src/main/java/io/reactivex/rxjava3/plugins/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/plugins/package-info.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ /** diff --git a/src/main/java/io/reactivex/rxjava3/processors/AsyncProcessor.java b/src/main/java/io/reactivex/rxjava3/processors/AsyncProcessor.java index 3461c146d6a..b20c8b23aed 100644 --- a/src/main/java/io/reactivex/rxjava3/processors/AsyncProcessor.java +++ b/src/main/java/io/reactivex/rxjava3/processors/AsyncProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.processors; import java.util.concurrent.atomic.AtomicReference; @@ -113,7 +114,7 @@ *

* @param the value type */ -public final class AsyncProcessor extends FlowableProcessor { +public final class AsyncProcessor<@NonNull T> extends FlowableProcessor { @SuppressWarnings("rawtypes") static final AsyncSubscription[] EMPTY = new AsyncSubscription[0]; @@ -150,7 +151,7 @@ public static AsyncProcessor create() { } @Override - public void onSubscribe(Subscription s) { + public void onSubscribe(@NonNull Subscription s) { if (subscribers.get() == TERMINATED) { s.cancel(); return; @@ -160,7 +161,7 @@ public void onSubscribe(Subscription s) { } @Override - public void onNext(T t) { + public void onNext(@NonNull T t) { ExceptionHelper.nullCheck(t, "onNext called with a null value."); if (subscribers.get() == TERMINATED) { return; @@ -170,7 +171,7 @@ public void onNext(T t) { @SuppressWarnings("unchecked") @Override - public void onError(Throwable t) { + public void onError(@NonNull Throwable t) { ExceptionHelper.nullCheck(t, "onError called with a null Throwable."); if (subscribers.get() == TERMINATED) { RxJavaPlugins.onError(t); @@ -228,7 +229,7 @@ public Throwable getThrowable() { } @Override - protected void subscribeActual(Subscriber s) { + protected void subscribeActual(@NonNull Subscriber s) { AsyncSubscription as = new AsyncSubscription<>(s, this); s.onSubscribe(as); if (add(as)) { @@ -336,7 +337,7 @@ public T getValue() { return subscribers.get() == TERMINATED ? value : null; } - static final class AsyncSubscription extends DeferredScalarSubscription { + static final class AsyncSubscription<@NonNull T> extends DeferredScalarSubscription { private static final long serialVersionUID = 5629876084736248016L; final AsyncProcessor parent; diff --git a/src/main/java/io/reactivex/rxjava3/processors/BehaviorProcessor.java b/src/main/java/io/reactivex/rxjava3/processors/BehaviorProcessor.java index 0b7e49ae2f3..2e5117ca560 100644 --- a/src/main/java/io/reactivex/rxjava3/processors/BehaviorProcessor.java +++ b/src/main/java/io/reactivex/rxjava3/processors/BehaviorProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -160,7 +160,7 @@ * @param * the type of item expected to be observed and emitted by the Processor */ -public final class BehaviorProcessor extends FlowableProcessor { +public final class BehaviorProcessor<@NonNull T> extends FlowableProcessor { final AtomicReference[]> subscribers; static final Object[] EMPTY_ARRAY = new Object[0]; @@ -306,17 +306,14 @@ public void onComplete() { } /** - * Tries to emit the item to all currently subscribed Subscribers if all of them - * has requested some value, returns false otherwise. - *

- * This method should be called in a sequential manner just like the onXXX methods - * of the PublishProcessor. + * Tries to emit the item to all currently subscribed {@link Subscriber}s if all of them + * has requested some value, returns {@code false} otherwise. *

- * Calling with a null value will terminate the PublishProcessor and a NullPointerException - * is signaled to the Subscribers. + * This method should be called in a sequential manner just like the {@code onXXX} methods + * of this {@code BehaviorProcessor}. *

History: 2.0.8 - experimental - * @param t the item to emit, not null - * @return true if the item was emitted to all Subscribers + * @param t the item to emit, not {@code null} + * @return {@code true} if the item was emitted to all {@code Subscriber}s * @throws NullPointerException if {@code t} is {@code null} * @since 2.2 */ @@ -455,16 +452,9 @@ void remove(BehaviorSubscription rs) { @SuppressWarnings("unchecked") BehaviorSubscription[] terminate(Object terminalValue) { - BehaviorSubscription[] a = subscribers.get(); - if (a != TERMINATED) { - a = subscribers.getAndSet(TERMINATED); - if (a != TERMINATED) { - // either this or atomics with lots of allocation - setCurrent(terminalValue); - } - } + setCurrent(terminalValue); - return a; + return subscribers.getAndSet(TERMINATED); } void setCurrent(Object o) { @@ -475,7 +465,7 @@ void setCurrent(Object o) { wl.unlock(); } - static final class BehaviorSubscription extends AtomicLong implements Subscription, NonThrowingPredicate { + static final class BehaviorSubscription<@NonNull T> extends AtomicLong implements Subscription, NonThrowingPredicate { private static final long serialVersionUID = 3293175281126227086L; @@ -600,7 +590,7 @@ public boolean test(Object o) { return false; } cancel(); - downstream.onError(new MissingBackpressureException("Could not deliver value due to lack of requests")); + downstream.onError(MissingBackpressureException.createDefault()); return true; } diff --git a/src/main/java/io/reactivex/rxjava3/processors/FlowableProcessor.java b/src/main/java/io/reactivex/rxjava3/processors/FlowableProcessor.java index 80db65e6520..2bfbb33bd0c 100644 --- a/src/main/java/io/reactivex/rxjava3/processors/FlowableProcessor.java +++ b/src/main/java/io/reactivex/rxjava3/processors/FlowableProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,7 @@ * * @param the item value type */ -public abstract class FlowableProcessor extends Flowable implements Processor, FlowableSubscriber { +public abstract class FlowableProcessor<@NonNull T> extends Flowable implements Processor, FlowableSubscriber { /** * Returns true if the FlowableProcessor has subscribers. diff --git a/src/main/java/io/reactivex/rxjava3/processors/MulticastProcessor.java b/src/main/java/io/reactivex/rxjava3/processors/MulticastProcessor.java index 7a6809b5d20..14a7a55ee2a 100644 --- a/src/main/java/io/reactivex/rxjava3/processors/MulticastProcessor.java +++ b/src/main/java/io/reactivex/rxjava3/processors/MulticastProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,10 +20,9 @@ import io.reactivex.rxjava3.annotations.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.internal.functions.ObjectHelper; -import io.reactivex.rxjava3.internal.fuseable.*; -import io.reactivex.rxjava3.internal.queue.*; import io.reactivex.rxjava3.internal.subscriptions.*; -import io.reactivex.rxjava3.internal.util.ExceptionHelper; +import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** @@ -130,7 +129,7 @@ */ @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) -public final class MulticastProcessor extends FlowableProcessor { +public final class MulticastProcessor<@NonNull T> extends FlowableProcessor { final AtomicInteger wip; @@ -138,8 +137,6 @@ public final class MulticastProcessor extends FlowableProcessor { final AtomicReference[]> subscribers; - final AtomicBoolean once; - final int bufferSize; final int limit; @@ -233,7 +230,6 @@ public static MulticastProcessor create(int bufferSize, boolean refCount) this.subscribers = new AtomicReference<>(EMPTY); this.upstream = new AtomicReference<>(); this.refcount = refCount; - this.once = new AtomicBoolean(); } /** @@ -292,14 +288,14 @@ public void onSubscribe(@NonNull Subscription s) { @Override public void onNext(@NonNull T t) { - if (once.get()) { + if (done) { return; } if (fusionMode == QueueSubscription.NONE) { ExceptionHelper.nullCheck(t, "onNext called with a null value."); if (!queue.offer(t)) { SubscriptionHelper.cancel(upstream); - onError(new MissingBackpressureException()); + onError(MissingBackpressureException.createDefault()); return; } } @@ -317,7 +313,7 @@ public void onNext(@NonNull T t) { @CheckReturnValue public boolean offer(@NonNull T t) { ExceptionHelper.nullCheck(t, "offer called with a null value."); - if (once.get()) { + if (done) { return false; } if (fusionMode == QueueSubscription.NONE) { @@ -333,21 +329,19 @@ public boolean offer(@NonNull T t) { @Override public void onError(@NonNull Throwable t) { ExceptionHelper.nullCheck(t, "onError called with a null Throwable."); - if (once.compareAndSet(false, true)) { + if (!done) { error = t; done = true; drain(); - } else { - RxJavaPlugins.onError(t); + return; } + RxJavaPlugins.onError(t); } @Override public void onComplete() { - if (once.compareAndSet(false, true)) { - done = true; - drain(); - } + done = true; + drain(); } @Override @@ -359,19 +353,19 @@ public boolean hasSubscribers() { @Override @CheckReturnValue public boolean hasThrowable() { - return once.get() && error != null; + return done && error != null; } @Override @CheckReturnValue public boolean hasComplete() { - return once.get() && error == null; + return done && error == null; } @Override @CheckReturnValue public Throwable getThrowable() { - return once.get() ? error : null; + return done ? error : null; } @Override @@ -385,7 +379,7 @@ protected void subscribeActual(@NonNull Subscriber s) { drain(); } } else { - if (once.get() || !refcount) { + if (done) { Throwable ex = error; if (ex != null) { s.onError(ex); @@ -438,7 +432,7 @@ void remove(MulticastSubscription inner) { if (refcount) { if (subscribers.compareAndSet(a, TERMINATED)) { SubscriptionHelper.cancel(upstream); - once.set(true); + done = true; break; } } else { @@ -589,7 +583,7 @@ void drain() { } } - static final class MulticastSubscription extends AtomicLong implements Subscription { + static final class MulticastSubscription<@NonNull T> extends AtomicLong implements Subscription { private static final long serialVersionUID = -363282618957264509L; @@ -607,19 +601,9 @@ static final class MulticastSubscription extends AtomicLong implements Subscr @Override public void request(long n) { if (SubscriptionHelper.validate(n)) { - for (;;) { - long r = get(); - if (r == Long.MIN_VALUE || r == Long.MAX_VALUE) { - break; - } - long u = r + n; - if (u < 0L) { - u = Long.MAX_VALUE; - } - if (compareAndSet(r, u)) { - parent.drain(); - break; - } + long r = BackpressureHelper.addCancel(this, n); + if (r != Long.MIN_VALUE && r != Long.MAX_VALUE) { + parent.drain(); } } } diff --git a/src/main/java/io/reactivex/rxjava3/processors/PublishProcessor.java b/src/main/java/io/reactivex/rxjava3/processors/PublishProcessor.java index 0a73cf1bf88..73507844d20 100644 --- a/src/main/java/io/reactivex/rxjava3/processors/PublishProcessor.java +++ b/src/main/java/io/reactivex/rxjava3/processors/PublishProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.processors; import java.util.concurrent.atomic.*; @@ -106,7 +107,7 @@ * @param the value type multicasted to Subscribers. * @see MulticastProcessor */ -public final class PublishProcessor extends FlowableProcessor { +public final class PublishProcessor<@NonNull T> extends FlowableProcessor { /** The terminated indicator for the subscribers array. */ @SuppressWarnings("rawtypes") static final PublishSubscription[] TERMINATED = new PublishSubscription[0]; @@ -270,17 +271,14 @@ public void onComplete() { } /** - * Tries to emit the item to all currently subscribed Subscribers if all of them - * has requested some value, returns false otherwise. - *

- * This method should be called in a sequential manner just like the onXXX methods - * of the PublishProcessor. + * Tries to emit the item to all currently subscribed {@link Subscriber}s if all of them + * has requested some value, returns {@code false} otherwise. *

- * Calling with a null value will terminate the PublishProcessor and a NullPointerException - * is signaled to the Subscribers. + * This method should be called in a sequential manner just like the {@code onXXX} methods + * of this {@code PublishProcessor}. *

History: 2.0.8 - experimental - * @param t the item to emit, not null - * @return true if the item was emitted to all Subscribers + * @param t the item to emit, not {@code null} + * @return {@code true} if the item was emitted to all {@code Subscriber}s * @throws NullPointerException if {@code t} is {@code null} * @since 2.2 */ @@ -336,7 +334,7 @@ public boolean hasComplete() { * * @param the value type */ - static final class PublishSubscription extends AtomicLong implements Subscription { + static final class PublishSubscription<@NonNull T> extends AtomicLong implements Subscription { private static final long serialVersionUID = 3562861878281475070L; /** The actual subscriber. */ @@ -364,7 +362,7 @@ public void onNext(T t) { BackpressureHelper.producedCancel(this, 1); } else { cancel(); - downstream.onError(new MissingBackpressureException("Could not emit value due to lack of requests")); + downstream.onError(MissingBackpressureException.createDefault()); } } diff --git a/src/main/java/io/reactivex/rxjava3/processors/ReplayProcessor.java b/src/main/java/io/reactivex/rxjava3/processors/ReplayProcessor.java index b7880d68339..ae6a7d3960a 100644 --- a/src/main/java/io/reactivex/rxjava3/processors/ReplayProcessor.java +++ b/src/main/java/io/reactivex/rxjava3/processors/ReplayProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -141,7 +141,7 @@ * * @param the value type */ -public final class ReplayProcessor extends FlowableProcessor { +public final class ReplayProcessor<@NonNull T> extends FlowableProcessor { /** An empty array to avoid allocation in getValues(). */ private static final Object[] EMPTY_ARRAY = new Object[0]; @@ -190,10 +190,12 @@ public static ReplayProcessor create() { * @param capacityHint * the initial buffer capacity * @return the created processor + * @throws IllegalArgumentException if {@code capacityHint} is non-positive */ @CheckReturnValue @NonNull public static ReplayProcessor create(int capacityHint) { + ObjectHelper.verifyPositive(capacityHint, "capacityHint"); return new ReplayProcessor<>(new UnboundedReplayBuffer<>(capacityHint)); } @@ -216,10 +218,12 @@ public static ReplayProcessor create(int capacityHint) { * @param maxSize * the maximum number of buffered items * @return the created processor + * @throws IllegalArgumentException if {@code maxSize} is non-positive */ @CheckReturnValue @NonNull public static ReplayProcessor createWithSize(int maxSize) { + ObjectHelper.verifyPositive(maxSize, "maxSize"); return new ReplayProcessor<>(new SizeBoundReplayBuffer<>(maxSize)); } @@ -272,10 +276,15 @@ public static ReplayProcessor createWithSize(int maxSize) { * @param scheduler * the {@link Scheduler} that provides the current time * @return the created processor + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code maxAge} is non-positive */ @CheckReturnValue @NonNull public static ReplayProcessor createWithTime(long maxAge, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + ObjectHelper.verifyPositive(maxAge, "maxAge"); + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); return new ReplayProcessor<>(new SizeAndTimeBoundReplayBuffer<>(Integer.MAX_VALUE, maxAge, unit, scheduler)); } @@ -312,10 +321,16 @@ public static ReplayProcessor createWithTime(long maxAge, @NonNull TimeUn * @param scheduler * the {@link Scheduler} that provides the current time * @return the created processor + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code maxAge} or {@code maxSize} is non-positive */ @CheckReturnValue @NonNull public static ReplayProcessor createWithTimeAndSize(long maxAge, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, int maxSize) { + ObjectHelper.verifyPositive(maxSize, "maxSize"); + ObjectHelper.verifyPositive(maxAge, "maxAge"); + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); return new ReplayProcessor<>(new SizeAndTimeBoundReplayBuffer<>(maxSize, maxAge, unit, scheduler)); } @@ -569,7 +584,7 @@ void remove(ReplaySubscription rs) { * * @param the value type */ - interface ReplayBuffer { + interface ReplayBuffer<@NonNull T> { void next(T value); @@ -597,7 +612,7 @@ interface ReplayBuffer { void trimHead(); } - static final class ReplaySubscription extends AtomicInteger implements Subscription { + static final class ReplaySubscription<@NonNull T> extends AtomicInteger implements Subscription { private static final long serialVersionUID = 466549804534799122L; final Subscriber downstream; @@ -645,7 +660,7 @@ static final class UnboundedReplayBuffer volatile int size; UnboundedReplayBuffer(int capacityHint) { - this.buffer = new ArrayList<>(ObjectHelper.verifyPositive(capacityHint, "capacityHint")); + this.buffer = new ArrayList<>(capacityHint); } @Override @@ -831,7 +846,7 @@ static final class TimedNode extends AtomicReference> { } } - static final class SizeBoundReplayBuffer + static final class SizeBoundReplayBuffer<@NonNull T> implements ReplayBuffer { final int maxSize; @@ -845,7 +860,7 @@ static final class SizeBoundReplayBuffer volatile boolean done; SizeBoundReplayBuffer(int maxSize) { - this.maxSize = ObjectHelper.verifyPositive(maxSize, "maxSize"); + this.maxSize = maxSize; Node h = new Node<>(null); this.tail = h; this.head = h; @@ -1061,10 +1076,10 @@ static final class SizeAndTimeBoundReplayBuffer volatile boolean done; SizeAndTimeBoundReplayBuffer(int maxSize, long maxAge, TimeUnit unit, Scheduler scheduler) { - this.maxSize = ObjectHelper.verifyPositive(maxSize, "maxSize"); - this.maxAge = ObjectHelper.verifyPositive(maxAge, "maxAge"); - this.unit = Objects.requireNonNull(unit, "unit is null"); - this.scheduler = Objects.requireNonNull(scheduler, "scheduler is null"); + this.maxSize = maxSize; + this.maxAge = maxAge; + this.unit = unit; + this.scheduler = scheduler; TimedNode h = new TimedNode<>(null, 0L); this.tail = h; this.head = h; @@ -1086,10 +1101,6 @@ void trim() { break; } TimedNode next = h.get(); - if (next == null) { - head = h; - break; - } if (next.time > limit) { head = h; diff --git a/src/main/java/io/reactivex/rxjava3/processors/SerializedProcessor.java b/src/main/java/io/reactivex/rxjava3/processors/SerializedProcessor.java index e7740b65233..e40d935c51c 100644 --- a/src/main/java/io/reactivex/rxjava3/processors/SerializedProcessor.java +++ b/src/main/java/io/reactivex/rxjava3/processors/SerializedProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/processors/UnicastProcessor.java b/src/main/java/io/reactivex/rxjava3/processors/UnicastProcessor.java index eab7da4f05a..ad7e7f66b66 100644 --- a/src/main/java/io/reactivex/rxjava3/processors/UnicastProcessor.java +++ b/src/main/java/io/reactivex/rxjava3/processors/UnicastProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,10 +20,10 @@ import io.reactivex.rxjava3.annotations.*; import io.reactivex.rxjava3.internal.functions.*; -import io.reactivex.rxjava3.internal.fuseable.QueueSubscription; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.*; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** @@ -147,7 +147,7 @@ * @param the value type received and emitted by this Processor subclass * @since 2.0 */ -public final class UnicastProcessor extends FlowableProcessor { +public final class UnicastProcessor<@NonNull T> extends FlowableProcessor { final SpscLinkedArrayQueue queue; @@ -179,7 +179,7 @@ public final class UnicastProcessor extends FlowableProcessor { @CheckReturnValue @NonNull public static UnicastProcessor create() { - return create(bufferSize(), Functions.EMPTY_RUNNABLE, true); + return new UnicastProcessor<>(bufferSize(), null, true); } /** @@ -187,11 +187,13 @@ public static UnicastProcessor create() { * @param the value type * @param capacityHint the hint to size the internal unbounded buffer * @return an UnicastProcessor instance + * @throws IllegalArgumentException if {@code capacityHint} is non-positive */ @CheckReturnValue @NonNull public static UnicastProcessor create(int capacityHint) { - return create(capacityHint, Functions.EMPTY_RUNNABLE, true); + ObjectHelper.verifyPositive(capacityHint, "capacityHint"); + return new UnicastProcessor<>(capacityHint, null, true); } /** @@ -205,7 +207,7 @@ public static UnicastProcessor create(int capacityHint) { @CheckReturnValue @NonNull public static UnicastProcessor create(boolean delayError) { - return create(bufferSize(), Functions.EMPTY_RUNNABLE, delayError); + return new UnicastProcessor<>(bufferSize(), null, delayError); } /** @@ -220,6 +222,8 @@ public static UnicastProcessor create(boolean delayError) { * @param capacityHint the hint to size the internal unbounded buffer * @param onTerminate the non null callback * @return an UnicastProcessor instance + * @throws NullPointerException if {@code onTerminate} is {@code null} + * @throws IllegalArgumentException if {@code capacityHint} is non-positive */ @CheckReturnValue @NonNull @@ -240,11 +244,15 @@ public static UnicastProcessor create(int capacityHint, @NonNull Runnable * @param onTerminate the non null callback * @param delayError deliver pending onNext events before onError * @return an UnicastProcessor instance + * @throws NullPointerException if {@code onTerminate} is {@code null} + * @throws IllegalArgumentException if {@code capacityHint} is non-positive * @since 2.2 */ @CheckReturnValue @NonNull public static UnicastProcessor create(int capacityHint, @NonNull Runnable onTerminate, boolean delayError) { + Objects.requireNonNull(onTerminate, "onTerminate"); + ObjectHelper.verifyPositive(capacityHint, "capacityHint"); return new UnicastProcessor<>(capacityHint, onTerminate, delayError); } @@ -258,8 +266,8 @@ public static UnicastProcessor create(int capacityHint, @NonNull Runnable * @since 2.2 */ UnicastProcessor(int capacityHint, Runnable onTerminate, boolean delayError) { - this.queue = new SpscLinkedArrayQueue<>(ObjectHelper.verifyPositive(capacityHint, "capacityHint")); - this.onTerminate = new AtomicReference<>(Objects.requireNonNull(onTerminate, "onTerminate")); + this.queue = new SpscLinkedArrayQueue<>(capacityHint); + this.onTerminate = new AtomicReference<>(onTerminate); this.delayError = delayError; this.downstream = new AtomicReference<>(); this.once = new AtomicBoolean(); diff --git a/src/main/java/io/reactivex/rxjava3/processors/package-info.java b/src/main/java/io/reactivex/rxjava3/processors/package-info.java index be2bb7c9543..f4119c9ba8b 100644 --- a/src/main/java/io/reactivex/rxjava3/processors/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/processors/package-info.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ /** diff --git a/src/main/java/io/reactivex/rxjava3/schedulers/SchedulerRunnableIntrospection.java b/src/main/java/io/reactivex/rxjava3/schedulers/SchedulerRunnableIntrospection.java index aec31701380..97f8efcc9da 100644 --- a/src/main/java/io/reactivex/rxjava3/schedulers/SchedulerRunnableIntrospection.java +++ b/src/main/java/io/reactivex/rxjava3/schedulers/SchedulerRunnableIntrospection.java @@ -1,8 +1,11 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at + * * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software distributed under the License is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. diff --git a/src/main/java/io/reactivex/rxjava3/schedulers/Schedulers.java b/src/main/java/io/reactivex/rxjava3/schedulers/Schedulers.java index 4d4c3517a59..cb256524048 100644 --- a/src/main/java/io/reactivex/rxjava3/schedulers/Schedulers.java +++ b/src/main/java/io/reactivex/rxjava3/schedulers/Schedulers.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,22 +22,27 @@ import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** - * Static factory methods for returning standard Scheduler instances. + * Static factory methods for returning standard {@link Scheduler} instances. *

* The initial and runtime values of the various scheduler types can be overridden via the * {@code RxJavaPlugins.setInit(scheduler name)SchedulerHandler()} and * {@code RxJavaPlugins.set(scheduler name)SchedulerHandler()} respectively. + * Note that overriding any initial {@code Scheduler} via the {@link RxJavaPlugins} + * has to happen before the {@code Schedulers} class is accessed. *

* Supported system properties ({@code System.getProperty()}): *

    - *
  • {@code rx3.io-keep-alive-time} (long): sets the keep-alive time of the {@link #io()} Scheduler workers, default is {@link IoScheduler#KEEP_ALIVE_TIME_DEFAULT}
  • - *
  • {@code rx3.io-priority} (int): sets the thread priority of the {@link #io()} Scheduler, default is {@link Thread#NORM_PRIORITY}
  • - *
  • {@code rx3.computation-threads} (int): sets the number of threads in the {@link #computation()} Scheduler, default is the number of available CPUs
  • - *
  • {@code rx3.computation-priority} (int): sets the thread priority of the {@link #computation()} Scheduler, default is {@link Thread#NORM_PRIORITY}
  • - *
  • {@code rx3.newthread-priority} (int): sets the thread priority of the {@link #newThread()} Scheduler, default is {@link Thread#NORM_PRIORITY}
  • - *
  • {@code rx3.single-priority} (int): sets the thread priority of the {@link #single()} Scheduler, default is {@link Thread#NORM_PRIORITY}
  • - *
  • {@code rx3.purge-enabled} (boolean): enables periodic purging of all Scheduler's backing thread pools, default is false
  • - *
  • {@code rx3.purge-period-seconds} (int): specifies the periodic purge interval of all Scheduler's backing thread pools, default is 1 second
  • + *
  • {@code rx3.io-keep-alive-time} (long): sets the keep-alive time of the {@link #io()} {@code Scheduler} workers, default is {@link IoScheduler#KEEP_ALIVE_TIME_DEFAULT}
  • + *
  • {@code rx3.io-priority} (int): sets the thread priority of the {@link #io()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx3.io-scheduled-release} (boolean): {@code true} sets the worker release mode of the + * {@link #io()} {@code Scheduler} to scheduled, default is {@code false} for eager mode.
  • + *
  • {@code rx3.computation-threads} (int): sets the number of threads in the {@link #computation()} {@code Scheduler}, default is the number of available CPUs
  • + *
  • {@code rx3.computation-priority} (int): sets the thread priority of the {@link #computation()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx3.newthread-priority} (int): sets the thread priority of the {@link #newThread()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx3.single-priority} (int): sets the thread priority of the {@link #single()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx3.purge-enabled} (boolean): enables purging of all {@code Scheduler}'s backing thread pools, default is {@code true}
  • + *
  • {@code rx3.scheduler.use-nanotime} (boolean): {@code true} instructs {@code Scheduler} to use {@link System#nanoTime()} for {@link Scheduler#now(TimeUnit)}, + * instead of default {@link System#currentTimeMillis()} ({@code false})
  • *
*/ public final class Schedulers { @@ -105,32 +110,32 @@ private Schedulers() { * not disposing a worker that has timed/delayed tasks not cancelled by other means may leak resources and/or * execute those tasks "unexpectedly". *

- * If the {@link RxJavaPlugins#setFailOnNonBlockingScheduler(boolean)} is set to true, attempting to execute + * If the {@link RxJavaPlugins#setFailOnNonBlockingScheduler(boolean)} is set to {@code true}, attempting to execute * operators that block while running on this scheduler will throw an {@link IllegalStateException}. *

* You can control certain properties of this standard scheduler via system properties that have to be set - * before the {@link Schedulers} class is referenced in your code. + * before the {@code Schedulers} class is referenced in your code. *

Supported system properties ({@code System.getProperty()}): *

    - *
  • {@code rx3.computation-threads} (int): sets the number of threads in the {@code computation()} Scheduler, default is the number of available CPUs
  • - *
  • {@code rx3.computation-priority} (int): sets the thread priority of the {@code computation()} Scheduler, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx3.computation-threads} (int): sets the number of threads in the {@code computation()} {@code Scheduler}, default is the number of available CPUs
  • + *
  • {@code rx3.computation-priority} (int): sets the thread priority of the {@code computation()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • *
*

* The default value of this scheduler can be overridden at initialization time via the * {@link RxJavaPlugins#setInitComputationSchedulerHandler(io.reactivex.rxjava3.functions.Function)} plugin method. * Note that due to possible initialization cycles, using any of the other scheduler-returning methods will - * result in a {@code NullPointerException}. - * Once the {@link Schedulers} class has been initialized, you can override the returned {@link Scheduler} instance + * result in a {@link NullPointerException}. + * Once the {@code Schedulers} class has been initialized, you can override the returned {@code Scheduler} instance * via the {@link RxJavaPlugins#setComputationSchedulerHandler(io.reactivex.rxjava3.functions.Function)} method. *

- * It is possible to create a fresh instance of this scheduler with a custom ThreadFactory, via the + * It is possible to create a fresh instance of this scheduler with a custom {@link ThreadFactory}, via the * {@link RxJavaPlugins#createComputationScheduler(ThreadFactory)} method. Note that such custom * instances require a manual call to {@link Scheduler#shutdown()} to allow the JVM to exit or the * (J2EE) container to unload properly. *

Operators on the base reactive classes that use this scheduler are marked with the * @{@link io.reactivex.rxjava3.annotations.SchedulerSupport SchedulerSupport}({@link io.reactivex.rxjava3.annotations.SchedulerSupport#COMPUTATION COMPUTATION}) * annotation. - * @return a {@link Scheduler} meant for computation-bound work + * @return a {@code Scheduler} meant for computation-bound work */ @NonNull public static Scheduler computation() { @@ -146,7 +151,7 @@ public static Scheduler computation() { * that will try to reuse previously started instances used by the worker * returned by {@link io.reactivex.rxjava3.core.Scheduler#createWorker()} but otherwise will start a new backing * {@link ScheduledExecutorService} instance. Note that this scheduler may create an unbounded number - * of worker threads that can result in system slowdowns or {@code OutOfMemoryError}. Therefore, for casual uses + * of worker threads that can result in system slowdowns or {@link OutOfMemoryError}. Therefore, for casual uses * or when implementing an operator, the Worker instances must be disposed via {@link io.reactivex.rxjava3.core.Scheduler.Worker#dispose()}. *

* It is not recommended to perform computational work on this scheduler. Use {@link #computation()} instead. @@ -154,28 +159,46 @@ public static Scheduler computation() { * Unhandled errors will be delivered to the scheduler Thread's {@link java.lang.Thread.UncaughtExceptionHandler}. *

* You can control certain properties of this standard scheduler via system properties that have to be set - * before the {@link Schedulers} class is referenced in your code. + * before the {@code Schedulers} class is referenced in your code. *

Supported system properties ({@code System.getProperty()}): *

    - *
  • {@code rx3.io-keep-alive-time} (long): sets the keep-alive time of the {@code io()} Scheduler workers, default is {@link IoScheduler#KEEP_ALIVE_TIME_DEFAULT}
  • - *
  • {@code rx3.io-priority} (int): sets the thread priority of the {@code io()} Scheduler, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx3.io-keep-alive-time} (long): sets the keep-alive time of the {@code io()} {@code Scheduler} workers, default is {@link IoScheduler#KEEP_ALIVE_TIME_DEFAULT}
  • + *
  • {@code rx3.io-priority} (int): sets the thread priority of the {@code io()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx3.io-scheduled-release} (boolean): {@code true} sets the worker release mode of the + * {@code #io()} {@code Scheduler} to scheduled, default is {@code false} for eager mode.
  • *
*

* The default value of this scheduler can be overridden at initialization time via the * {@link RxJavaPlugins#setInitIoSchedulerHandler(io.reactivex.rxjava3.functions.Function)} plugin method. * Note that due to possible initialization cycles, using any of the other scheduler-returning methods will - * result in a {@code NullPointerException}. - * Once the {@link Schedulers} class has been initialized, you can override the returned {@link Scheduler} instance + * result in a {@link NullPointerException}. + * Once the {@code Schedulers} class has been initialized, you can override the returned {@code Scheduler} instance * via the {@link RxJavaPlugins#setIoSchedulerHandler(io.reactivex.rxjava3.functions.Function)} method. *

- * It is possible to create a fresh instance of this scheduler with a custom ThreadFactory, via the + * It is possible to create a fresh instance of this scheduler with a custom {@link ThreadFactory}, via the * {@link RxJavaPlugins#createIoScheduler(ThreadFactory)} method. Note that such custom * instances require a manual call to {@link Scheduler#shutdown()} to allow the JVM to exit or the * (J2EE) container to unload properly. *

Operators on the base reactive classes that use this scheduler are marked with the * @{@link io.reactivex.rxjava3.annotations.SchedulerSupport SchedulerSupport}({@link io.reactivex.rxjava3.annotations.SchedulerSupport#IO IO}) * annotation. - * @return a {@link Scheduler} meant for IO-bound work + *

+ * When the {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} is disposed, + * the underlying worker can be released to the cached worker pool in two modes: + *

    + *
  • In eager mode (default), the underlying worker is returned immediately to the cached worker pool + * and can be reused much quicker by operators. The drawback is that if the currently running task doesn't + * respond to interruption in time or at all, this may lead to delays or deadlock with the reuse use of the + * underlying worker. + *
  • + *
  • In scheduled mode (enabled via the system parameter {@code rx3.io-scheduled-release} + * set to {@code true}), the underlying worker is returned to the cached worker pool only after the currently running task + * has finished. This can help prevent premature reuse of the underlying worker and likely won't lead to delays or + * deadlock with such reuses. The drawback is that the delay in release may lead to an excess amount of underlying + * workers being created. + *
  • + *
+ * @return a {@code Scheduler} meant for IO-bound work */ @NonNull public static Scheduler io() { @@ -194,7 +217,7 @@ public static Scheduler io() { * by RxJava itself but may be found in external libraries. *

* This scheduler can't be overridden via an {@link RxJavaPlugins} method. - * @return a {@link Scheduler} that queues work on the current thread + * @return a {@code Scheduler} that queues work on the current thread */ @NonNull public static Scheduler trampoline() { @@ -207,33 +230,33 @@ public static Scheduler trampoline() { * The default implementation of this scheduler creates a new, single-threaded {@link ScheduledExecutorService} for * each invocation of the {@link Scheduler#scheduleDirect(Runnable)} (plus its overloads) and {@link Scheduler#createWorker()} * methods, thus an unbounded number of worker threads may be created that can - * result in system slowdowns or {@code OutOfMemoryError}. Therefore, for casual uses or when implementing an operator, + * result in system slowdowns or {@link OutOfMemoryError}. Therefore, for casual uses or when implementing an operator, * the Worker instances must be disposed via {@link io.reactivex.rxjava3.core.Scheduler.Worker#dispose()}. *

* Unhandled errors will be delivered to the scheduler Thread's {@link java.lang.Thread.UncaughtExceptionHandler}. *

* You can control certain properties of this standard scheduler via system properties that have to be set - * before the {@link Schedulers} class is referenced in your code. + * before the {@code Schedulers} class is referenced in your code. *

Supported system properties ({@code System.getProperty()}): *

    - *
  • {@code rx3.newthread-priority} (int): sets the thread priority of the {@code newThread()} Scheduler, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx3.newthread-priority} (int): sets the thread priority of the {@code newThread()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • *
*

* The default value of this scheduler can be overridden at initialization time via the * {@link RxJavaPlugins#setInitNewThreadSchedulerHandler(io.reactivex.rxjava3.functions.Function)} plugin method. * Note that due to possible initialization cycles, using any of the other scheduler-returning methods will - * result in a {@code NullPointerException}. - * Once the {@link Schedulers} class has been initialized, you can override the returned {@link Scheduler} instance + * result in a {@link NullPointerException}. + * Once the {@code Schedulers} class has been initialized, you can override the returned {@code Scheduler} instance * via the {@link RxJavaPlugins#setNewThreadSchedulerHandler(io.reactivex.rxjava3.functions.Function)} method. *

- * It is possible to create a fresh instance of this scheduler with a custom ThreadFactory, via the + * It is possible to create a fresh instance of this scheduler with a custom {@link ThreadFactory}, via the * {@link RxJavaPlugins#createNewThreadScheduler(ThreadFactory)} method. Note that such custom * instances require a manual call to {@link Scheduler#shutdown()} to allow the JVM to exit or the * (J2EE) container to unload properly. *

Operators on the base reactive classes that use this scheduler are marked with the * @{@link io.reactivex.rxjava3.annotations.SchedulerSupport SchedulerSupport}({@link io.reactivex.rxjava3.annotations.SchedulerSupport#NEW_THREAD NEW_TRHEAD}) * annotation. - * @return a {@link Scheduler} that creates new threads + * @return a {@code Scheduler} that creates new threads */ @NonNull public static Scheduler newThread() { @@ -247,7 +270,7 @@ public static Scheduler newThread() { * Uses: *

    *
  • event loop
  • - *
  • support Schedulers.from(Executor) and from(ExecutorService) with delayed scheduling
  • + *
  • support {@code Schedulers.from(}{@link Executor}{@code )} and {@code from(}{@link ExecutorService}{@code )} with delayed scheduling
  • *
  • support benchmarks that pipeline data from some thread to another thread and * avoid core-bashing of computation's round-robin nature
  • *
@@ -258,31 +281,31 @@ public static Scheduler newThread() { * not disposing a worker that has timed/delayed tasks not cancelled by other means may leak resources and/or * execute those tasks "unexpectedly". *

- * If the {@link RxJavaPlugins#setFailOnNonBlockingScheduler(boolean)} is set to true, attempting to execute + * If the {@link RxJavaPlugins#setFailOnNonBlockingScheduler(boolean)} is set to {@code true}, attempting to execute * operators that block while running on this scheduler will throw an {@link IllegalStateException}. *

* You can control certain properties of this standard scheduler via system properties that have to be set - * before the {@link Schedulers} class is referenced in your code. + * before the {@code Schedulers} class is referenced in your code. *

Supported system properties ({@code System.getProperty()}): *

    - *
  • {@code rx3.single-priority} (int): sets the thread priority of the {@code single()} Scheduler, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx3.single-priority} (int): sets the thread priority of the {@code single()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • *
*

* The default value of this scheduler can be overridden at initialization time via the * {@link RxJavaPlugins#setInitSingleSchedulerHandler(io.reactivex.rxjava3.functions.Function)} plugin method. * Note that due to possible initialization cycles, using any of the other scheduler-returning methods will - * result in a {@code NullPointerException}. - * Once the {@link Schedulers} class has been initialized, you can override the returned {@link Scheduler} instance + * result in a {@link NullPointerException}. + * Once the {@code Schedulers} class has been initialized, you can override the returned {@code Scheduler} instance * via the {@link RxJavaPlugins#setSingleSchedulerHandler(io.reactivex.rxjava3.functions.Function)} method. *

- * It is possible to create a fresh instance of this scheduler with a custom ThreadFactory, via the + * It is possible to create a fresh instance of this scheduler with a custom {@link ThreadFactory}, via the * {@link RxJavaPlugins#createSingleScheduler(ThreadFactory)} method. Note that such custom * instances require a manual call to {@link Scheduler#shutdown()} to allow the JVM to exit or the * (J2EE) container to unload properly. *

Operators on the base reactive classes that use this scheduler are marked with the * @{@link io.reactivex.rxjava3.annotations.SchedulerSupport SchedulerSupport}({@link io.reactivex.rxjava3.annotations.SchedulerSupport#SINGLE SINGLE}) * annotation. - * @return a {@link Scheduler} that shares a single backing thread. + * @return a {@code Scheduler} that shares a single backing thread. * @since 2.0 */ @NonNull @@ -291,11 +314,11 @@ public static Scheduler single() { } /** - * Wraps an {@link Executor} into a new Scheduler instance and delegates {@code schedule()} + * Wraps an {@link Executor} into a new {@link Scheduler} instance and delegates {@code schedule()} * calls to it. *

* If the provided executor doesn't support any of the more specific standard Java executor - * APIs, cancelling tasks scheduled by this scheduler can't be interrupted when they are + * APIs, tasks scheduled by this scheduler can't be interrupted when they are * executing but only prevented from running prior to that. In addition, tasks scheduled with * a time delay or periodically will use the {@link #single()} scheduler for the timed waiting * before posting the actual task to the given executor. @@ -304,24 +327,24 @@ public static Scheduler single() { * {@link #from(Executor, boolean)} overload to enable task interruption via this wrapper. *

* If the provided executor supports the standard Java {@link ExecutorService} API, - * cancelling tasks scheduled by this scheduler can be cancelled/interrupted by calling + * tasks scheduled by this scheduler can be cancelled/interrupted by calling * {@link io.reactivex.rxjava3.disposables.Disposable#dispose()}. In addition, tasks scheduled with * a time delay or periodically will use the {@link #single()} scheduler for the timed waiting * before posting the actual task to the given executor. *

* If the provided executor supports the standard Java {@link ScheduledExecutorService} API, - * cancelling tasks scheduled by this scheduler can be cancelled/interrupted by calling + * tasks scheduled by this scheduler can be cancelled/interrupted by calling * {@link io.reactivex.rxjava3.disposables.Disposable#dispose()}. In addition, tasks scheduled with * a time delay or periodically will use the provided executor. Note, however, if the provided * {@code ScheduledExecutorService} instance is not single threaded, tasks scheduled * with a time delay close to each other may end up executing in different order than * the original schedule() call was issued. This limitation may be lifted in a future patch. *

- * The implementation of the Worker of this wrapper Scheduler is eager and will execute as many + * The implementation of the Worker of this wrapper {@code Scheduler} is eager and will execute as many * non-delayed tasks as it can, which may result in a longer than expected occupation of a - * thread of the given backing Executor. In other terms, it does not allow per-Runnable fairness - * in case the worker runs on a shared underlying thread of the Executor. - * See {@link #from(Executor, boolean, boolean)} to create a wrapper that uses the underlying Executor + * thread of the given backing {@code Executor}. In other terms, it does not allow per-{@link Runnable} fairness + * in case the worker runs on a shared underlying thread of the {@code Executor}. + * See {@link #from(Executor, boolean, boolean)} to create a wrapper that uses the underlying {@code Executor} * more fairly. *

* Starting, stopping and restarting this scheduler is not supported (no-op) and the provided @@ -340,26 +363,40 @@ public static Scheduler single() { * } * *

+ * Note that the provided {@code Executor} should avoid throwing a {@link RejectedExecutionException} + * (for example, by shutting it down prematurely or using a bounded-queue {@code ExecutorService}) + * because such circumstances prevent RxJava from progressing flow-related activities correctly. + * If the {@link Executor#execute(Runnable)} or {@link ExecutorService#submit(Callable)} throws, + * the {@code RejectedExecutionException} is routed to the global error handler via + * {@link RxJavaPlugins#onError(Throwable)}. To avoid shutdown-related problems, it is recommended + * all flows using the returned {@code Scheduler} to be canceled/disposed before the underlying + * {@code Executor} is shut down. To avoid problems due to the {@code Executor} having a bounded-queue, + * it is recommended to rephrase the flow to utilize backpressure as the means to limit outstanding work. + *

* This type of scheduler is less sensitive to leaking {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} instances, although * not disposing a worker that has timed/delayed tasks not cancelled by other means may leak resources and/or * execute those tasks "unexpectedly". *

- * Note that this method returns a new {@link Scheduler} instance, even for the same {@link Executor} instance. + * Note that this method returns a new {@code Scheduler} instance, even for the same {@code Executor} instance. + *

+ * It is possible to wrap an {@code Executor} into a {@code Scheduler} without triggering the initialization of all the + * standard schedulers by using the {@link RxJavaPlugins#createExecutorScheduler(Executor, boolean, boolean)} method + * before the {@code Schedulers} class itself is accessed. * @param executor * the executor to wrap - * @return the new Scheduler wrapping the Executor + * @return the new {@code Scheduler} wrapping the {@code Executor} * @see #from(Executor, boolean, boolean) */ @NonNull public static Scheduler from(@NonNull Executor executor) { - return new ExecutorScheduler(executor, false, false); + return from(executor, false, false); } /** - * Wraps an {@link Executor} into a new Scheduler instance and delegates {@code schedule()} + * Wraps an {@link Executor} into a new {@link Scheduler} instance and delegates {@code schedule()} * calls to it. *

- * The tasks scheduled by the returned {@link Scheduler} and its {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} + * The tasks scheduled by the returned {@code Scheduler} and its {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} * can be optionally interrupted. *

* If the provided executor doesn't support any of the more specific standard Java executor @@ -368,24 +405,24 @@ public static Scheduler from(@NonNull Executor executor) { * before posting the actual task to the given executor. *

* If the provided executor supports the standard Java {@link ExecutorService} API, - * canceling tasks scheduled by this scheduler can be cancelled/interrupted by calling + * tasks scheduled by this scheduler can be cancelled/interrupted by calling * {@link io.reactivex.rxjava3.disposables.Disposable#dispose()}. In addition, tasks scheduled with * a time delay or periodically will use the {@link #single()} scheduler for the timed waiting * before posting the actual task to the given executor. *

* If the provided executor supports the standard Java {@link ScheduledExecutorService} API, - * canceling tasks scheduled by this scheduler can be cancelled/interrupted by calling + * tasks scheduled by this scheduler can be cancelled/interrupted by calling * {@link io.reactivex.rxjava3.disposables.Disposable#dispose()}. In addition, tasks scheduled with * a time delay or periodically will use the provided executor. Note, however, if the provided * {@code ScheduledExecutorService} instance is not single threaded, tasks scheduled * with a time delay close to each other may end up executing in different order than * the original schedule() call was issued. This limitation may be lifted in a future patch. *

- * The implementation of the Worker of this wrapper Scheduler is eager and will execute as many + * The implementation of the {@code Worker} of this wrapper {@code Scheduler} is eager and will execute as many * non-delayed tasks as it can, which may result in a longer than expected occupation of a - * thread of the given backing Executor. In other terms, it does not allow per-Runnable fairness - * in case the worker runs on a shared underlying thread of the Executor. - * See {@link #from(Executor, boolean, boolean)} to create a wrapper that uses the underlying Executor + * thread of the given backing {@code Executor}. In other terms, it does not allow per-{@link Runnable} fairness + * in case the worker runs on a shared underlying thread of the {@code Executor}. + * See {@link #from(Executor, boolean, boolean)} to create a wrapper that uses the underlying {@code Executor} * more fairly. *

* Starting, stopping and restarting this scheduler is not supported (no-op) and the provided @@ -404,30 +441,44 @@ public static Scheduler from(@NonNull Executor executor) { * } * *

+ * Note that the provided {@code Executor} should avoid throwing a {@link RejectedExecutionException} + * (for example, by shutting it down prematurely or using a bounded-queue {@code ExecutorService}) + * because such circumstances prevent RxJava from progressing flow-related activities correctly. + * If the {@link Executor#execute(Runnable)} or {@link ExecutorService#submit(Callable)} throws, + * the {@code RejectedExecutionException} is routed to the global error handler via + * {@link RxJavaPlugins#onError(Throwable)}. To avoid shutdown-related problems, it is recommended + * all flows using the returned {@code Scheduler} to be canceled/disposed before the underlying + * {@code Executor} is shut down. To avoid problems due to the {@code Executor} having a bounded-queue, + * it is recommended to rephrase the flow to utilize backpressure as the means to limit outstanding work. + *

* This type of scheduler is less sensitive to leaking {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} instances, although * not disposing a worker that has timed/delayed tasks not cancelled by other means may leak resources and/or * execute those tasks "unexpectedly". *

- * Note that this method returns a new {@link Scheduler} instance, even for the same {@link Executor} instance. + * Note that this method returns a new {@code Scheduler} instance, even for the same {@code Executor} instance. + *

+ * It is possible to wrap an {@code Executor} into a {@code Scheduler} without triggering the initialization of all the + * standard schedulers by using the {@link RxJavaPlugins#createExecutorScheduler(Executor, boolean, boolean)} method + * before the {@code Schedulers} class itself is accessed. *

History: 2.2.6 - experimental * @param executor * the executor to wrap - * @param interruptibleWorker if {@code true} the tasks submitted to the {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} will + * @param interruptibleWorker if {@code true}, the tasks submitted to the {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} will * be interrupted when the task is disposed. - * @return the new Scheduler wrapping the Executor + * @return the new {@code Scheduler} wrapping the {@code Executor} * @since 3.0.0 * @see #from(Executor, boolean, boolean) */ @NonNull public static Scheduler from(@NonNull Executor executor, boolean interruptibleWorker) { - return new ExecutorScheduler(executor, interruptibleWorker, false); + return from(executor, interruptibleWorker, false); } /** - * Wraps an {@link Executor} into a new Scheduler instance and delegates {@code schedule()} + * Wraps an {@link Executor} into a new {@link Scheduler} instance and delegates {@code schedule()} * calls to it. *

- * The tasks scheduled by the returned {@link Scheduler} and its {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} + * The tasks scheduled by the returned {@code Scheduler} and its {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} * can be optionally interrupted. *

* If the provided executor doesn't support any of the more specific standard Java executor @@ -436,27 +487,27 @@ public static Scheduler from(@NonNull Executor executor, boolean interruptibleWo * before posting the actual task to the given executor. *

* If the provided executor supports the standard Java {@link ExecutorService} API, - * canceling tasks scheduled by this scheduler can be cancelled/interrupted by calling + * tasks scheduled by this scheduler can be cancelled/interrupted by calling * {@link io.reactivex.rxjava3.disposables.Disposable#dispose()}. In addition, tasks scheduled with * a time delay or periodically will use the {@link #single()} scheduler for the timed waiting * before posting the actual task to the given executor. *

* If the provided executor supports the standard Java {@link ScheduledExecutorService} API, - * canceling tasks scheduled by this scheduler can be cancelled/interrupted by calling + * tasks scheduled by this scheduler can be cancelled/interrupted by calling * {@link io.reactivex.rxjava3.disposables.Disposable#dispose()}. In addition, tasks scheduled with * a time delay or periodically will use the provided executor. Note, however, if the provided * {@code ScheduledExecutorService} instance is not single threaded, tasks scheduled * with a time delay close to each other may end up executing in different order than * the original schedule() call was issued. This limitation may be lifted in a future patch. *

- * The implementation of the Worker of this wrapper Scheduler can operate in both eager (non-fair) and + * The implementation of the Worker of this wrapper {@code Scheduler} can operate in both eager (non-fair) and * fair modes depending on the specified parameter. In eager mode, it will execute as many * non-delayed tasks as it can, which may result in a longer than expected occupation of a - * thread of the given backing Executor. In other terms, it does not allow per-Runnable fairness - * in case the worker runs on a shared underlying thread of the Executor. In fair mode, + * thread of the given backing {@code Executor}. In other terms, it does not allow per-{@link Runnable} fairness + * in case the worker runs on a shared underlying thread of the {@code Executor}. In fair mode, * non-delayed tasks will still be executed in a FIFO and non-overlapping manner, but after each task, - * the execution for the next task is rescheduled with the same underlying Executor, allowing interleaving - * from both the same Scheduler or other external usages of the underlying Executor. + * the execution for the next task is rescheduled with the same underlying {@code Executor}, allowing interleaving + * from both the same {@code Scheduler} or other external usages of the underlying {@code Executor}. *

* Starting, stopping and restarting this scheduler is not supported (no-op) and the provided * executor's lifecycle must be managed externally: @@ -474,28 +525,43 @@ public static Scheduler from(@NonNull Executor executor, boolean interruptibleWo * } * *

+ * Note that the provided {@code Executor} should avoid throwing a {@link RejectedExecutionException} + * (for example, by shutting it down prematurely or using a bounded-queue {@code ExecutorService}) + * because such circumstances prevent RxJava from progressing flow-related activities correctly. + * If the {@link Executor#execute(Runnable)} or {@link ExecutorService#submit(Callable)} throws, + * the {@code RejectedExecutionException} is routed to the global error handler via + * {@link RxJavaPlugins#onError(Throwable)}. To avoid shutdown-related problems, it is recommended + * all flows using the returned {@code Scheduler} to be canceled/disposed before the underlying + * {@code Executor} is shut down. To avoid problems due to the {@code Executor} having a bounded-queue, + * it is recommended to rephrase the flow to utilize backpressure as the means to limit outstanding work. + *

* This type of scheduler is less sensitive to leaking {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} instances, although * not disposing a worker that has timed/delayed tasks not cancelled by other means may leak resources and/or * execute those tasks "unexpectedly". *

- * Note that this method returns a new {@link Scheduler} instance, even for the same {@link Executor} instance. + * Note that this method returns a new {@code Scheduler} instance, even for the same {@code Executor} instance. + *

+ * It is possible to wrap an {@code Executor} into a {@code Scheduler} without triggering the initialization of all the + * standard schedulers by using the {@link RxJavaPlugins#createExecutorScheduler(Executor, boolean, boolean)} method + * before the {@code Schedulers} class itself is accessed. + * * @param executor * the executor to wrap - * @param interruptibleWorker if {@code true} the tasks submitted to the {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} will + * @param interruptibleWorker if {@code true}, the tasks submitted to the {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} will * be interrupted when the task is disposed. - * @param fair if {@code true} tasks submitted to the will be executed by the underlying {@link Executor} one after the other, still + * @param fair if {@code true}, tasks submitted to the {@code Scheduler} or {@code Worker} will be executed by the underlying {@code Executor} one after the other, still * in a FIFO and non-overlapping manner, but allows interleaving with other tasks submitted to the underlying {@code Executor}. * If {@code false}, the underlying FIFO scheme will execute as many tasks as it can before giving up the underlying {@code Executor} thread. - * @return the new Scheduler wrapping the Executor + * @return the new {@code Scheduler} wrapping the {@code Executor} * @since 3.0.0 */ @NonNull public static Scheduler from(@NonNull Executor executor, boolean interruptibleWorker, boolean fair) { - return new ExecutorScheduler(executor, interruptibleWorker, fair); + return RxJavaPlugins.createExecutorScheduler(executor, interruptibleWorker, fair); } /** - * Shuts down the standard Schedulers. + * Shuts down the standard {@link Scheduler}s. *

The operation is idempotent and thread-safe. */ public static void shutdown() { @@ -504,11 +570,10 @@ public static void shutdown() { newThread().shutdown(); single().shutdown(); trampoline().shutdown(); - SchedulerPoolFactory.shutdown(); } /** - * Starts the standard Schedulers. + * Starts the standard {@link Scheduler}s. *

The operation is idempotent and thread-safe. */ public static void start() { @@ -517,7 +582,6 @@ public static void start() { newThread().start(); single().start(); trampoline().start(); - SchedulerPoolFactory.start(); } static final class IOTask implements Supplier { diff --git a/src/main/java/io/reactivex/rxjava3/schedulers/TestScheduler.java b/src/main/java/io/reactivex/rxjava3/schedulers/TestScheduler.java index 3e056652838..33aca58a489 100644 --- a/src/main/java/io/reactivex/rxjava3/schedulers/TestScheduler.java +++ b/src/main/java/io/reactivex/rxjava3/schedulers/TestScheduler.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,20 +15,28 @@ import java.util.Queue; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicReference; -import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.annotations.*; import io.reactivex.rxjava3.core.Scheduler; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.EmptyDisposable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** * A special, non thread-safe scheduler for testing operators that require * a scheduler without introducing real concurrency and allows manually advancing * a virtual time. + *

+ * By default, the tasks submitted via the various {@code schedule} methods are not + * wrapped by the {@link RxJavaPlugins#onSchedule(Runnable)} hook. To enable this behavior, + * create a {@code TestScheduler} via {@link #TestScheduler(boolean)} or {@link #TestScheduler(long, TimeUnit, boolean)}. */ public final class TestScheduler extends Scheduler { /** The ordered queue for the runnable tasks. */ final Queue queue = new PriorityBlockingQueue<>(11); + /** Use the {@link RxJavaPlugins#onSchedule(Runnable)} hook when scheduling tasks. */ + final boolean useOnScheduleHook; /** The per-scheduler global order counter. */ long counter; // Storing time in nanoseconds internally. @@ -38,7 +46,20 @@ public final class TestScheduler extends Scheduler { * Creates a new TestScheduler with initial virtual time of zero. */ public TestScheduler() { - // No-op. + this(false); + } + + /** + * Creates a new TestScheduler with the option to use the + * {@link RxJavaPlugins#onSchedule(Runnable)} hook when scheduling tasks. + *

History: 3.0.10 - experimental + * @param useOnScheduleHook if {@code true}, the tasks submitted to this + * TestScheduler is wrapped via the + * {@link RxJavaPlugins#onSchedule(Runnable)} hook + * @since 3.1.0 + */ + public TestScheduler(boolean useOnScheduleHook) { + this.useOnScheduleHook = useOnScheduleHook; } /** @@ -50,7 +71,26 @@ public TestScheduler() { * the units of time that {@code delayTime} is expressed in */ public TestScheduler(long delayTime, TimeUnit unit) { + this(delayTime, unit, false); + } + + /** + * Creates a new TestScheduler with the specified initial virtual time + * and with the option to use the + * {@link RxJavaPlugins#onSchedule(Runnable)} hook when scheduling tasks. + *

History: 3.0.10 - experimental + * @param delayTime + * the point in time to move the Scheduler's clock to + * @param unit + * the units of time that {@code delayTime} is expressed in + * @param useOnScheduleHook if {@code true}, the tasks submitted to this + * TestScheduler is wrapped via the + * {@link RxJavaPlugins#onSchedule(Runnable)} hook + * @since 3.1.0 + */ + public TestScheduler(long delayTime, TimeUnit unit, boolean useOnScheduleHook) { time = unit.toNanos(delayTime); + this.useOnScheduleHook = useOnScheduleHook; } static final class TimedRunnable implements Comparable { @@ -163,10 +203,13 @@ public Disposable schedule(@NonNull Runnable run, long delayTime, @NonNull TimeU if (disposed) { return EmptyDisposable.INSTANCE; } + if (useOnScheduleHook) { + run = RxJavaPlugins.onSchedule(run); + } final TimedRunnable timedAction = new TimedRunnable(this, time + unit.toNanos(delayTime), run, counter++); queue.add(timedAction); - return Disposable.fromRunnable(new QueueRemove(timedAction)); + return new QueueRemove(timedAction); } @NonNull @@ -175,9 +218,12 @@ public Disposable schedule(@NonNull Runnable run) { if (disposed) { return EmptyDisposable.INSTANCE; } + if (useOnScheduleHook) { + run = RxJavaPlugins.onSchedule(run); + } final TimedRunnable timedAction = new TimedRunnable(this, 0, run, counter++); queue.add(timedAction); - return Disposable.fromRunnable(new QueueRemove(timedAction)); + return new QueueRemove(timedAction); } @Override @@ -185,16 +231,25 @@ public long now(@NonNull TimeUnit unit) { return TestScheduler.this.now(unit); } - final class QueueRemove implements Runnable { - final TimedRunnable timedAction; + final class QueueRemove extends AtomicReference implements Disposable { + + private static final long serialVersionUID = -7874968252110604360L; QueueRemove(TimedRunnable timedAction) { - this.timedAction = timedAction; + this.lazySet(timedAction); + } + + @Override + public void dispose() { + TimedRunnable tr = getAndSet(null); + if (tr != null) { + queue.remove(tr); + } } @Override - public void run() { - queue.remove(timedAction); + public boolean isDisposed() { + return get() == null; } } } diff --git a/src/main/java/io/reactivex/rxjava3/schedulers/Timed.java b/src/main/java/io/reactivex/rxjava3/schedulers/Timed.java index 814b223dcf5..3ef19409843 100644 --- a/src/main/java/io/reactivex/rxjava3/schedulers/Timed.java +++ b/src/main/java/io/reactivex/rxjava3/schedulers/Timed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -33,10 +33,10 @@ public final class Timed { * @param value the value to hold * @param time the time to hold * @param unit the time unit, not null - * @throws NullPointerException if unit is {@code null} + * @throws NullPointerException if {@code value} or {@code unit} is {@code null} */ public Timed(@NonNull T value, long time, @NonNull TimeUnit unit) { - this.value = value; + this.value = Objects.requireNonNull(value, "value is null"); this.time = time; this.unit = Objects.requireNonNull(unit, "unit is null"); } @@ -89,7 +89,7 @@ public boolean equals(Object other) { @Override public int hashCode() { - int h = value != null ? value.hashCode() : 0; + int h = value.hashCode(); h = h * 31 + (int)((time >>> 31) ^ time); h = h * 31 + unit.hashCode(); return h; diff --git a/src/main/java/io/reactivex/rxjava3/schedulers/package-info.java b/src/main/java/io/reactivex/rxjava3/schedulers/package-info.java index 4bbd9e0da2f..1f96d0fd2ab 100644 --- a/src/main/java/io/reactivex/rxjava3/schedulers/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/schedulers/package-info.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + /** * Contains notably the factory class of {@link io.reactivex.rxjava3.schedulers.Schedulers Schedulers} providing methods for * retrieving the standard scheduler instances, the {@link io.reactivex.rxjava3.schedulers.TestScheduler TestScheduler} for testing flows diff --git a/src/main/java/io/reactivex/rxjava3/subjects/AsyncSubject.java b/src/main/java/io/reactivex/rxjava3/subjects/AsyncSubject.java index cfeafcd4a8d..dd4957fd399 100644 --- a/src/main/java/io/reactivex/rxjava3/subjects/AsyncSubject.java +++ b/src/main/java/io/reactivex/rxjava3/subjects/AsyncSubject.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/subjects/BehaviorSubject.java b/src/main/java/io/reactivex/rxjava3/subjects/BehaviorSubject.java index d7f5516e7d4..2b19ecdd265 100644 --- a/src/main/java/io/reactivex/rxjava3/subjects/BehaviorSubject.java +++ b/src/main/java/io/reactivex/rxjava3/subjects/BehaviorSubject.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -28,7 +28,7 @@ * Subject that emits the most recent item it has observed and all subsequent observed items to each subscribed * {@link Observer}. *

- * + * *

* This subject does not have a public constructor by design; a new empty instance of this * {@code BehaviorSubject} can be created via the {@link #create()} method and @@ -59,9 +59,9 @@ * * TestObserver<Integer> to1 = observable.test(); * - * observable.onNext(1); + * subject.onNext(1); * // this will "clear" the cache - * observable.onNext(EMPTY); + * subject.onNext(EMPTY); * * TestObserver<Integer> to2 = observable.test(); * @@ -151,7 +151,7 @@ public final class BehaviorSubject extends Subject { final AtomicReference value; - final AtomicReference[]> subscribers; + final AtomicReference[]> observers; @SuppressWarnings("rawtypes") static final BehaviorDisposable[] EMPTY = new BehaviorDisposable[0]; @@ -176,7 +176,7 @@ public final class BehaviorSubject extends Subject { @CheckReturnValue @NonNull public static BehaviorSubject create() { - return new BehaviorSubject<>(); + return new BehaviorSubject<>(null); } /** @@ -189,38 +189,30 @@ public static BehaviorSubject create() { * the item that will be emitted first to any {@link Observer} as long as the * {@link BehaviorSubject} has not yet observed any items from its source {@code Observable} * @return the constructed {@link BehaviorSubject} + * @throws NullPointerException if {@code defaultValue} is {@code null} */ @CheckReturnValue @NonNull public static <@NonNull T> BehaviorSubject createDefault(T defaultValue) { + Objects.requireNonNull(defaultValue, "defaultValue is null"); return new BehaviorSubject<>(defaultValue); } /** * Constructs an empty BehaviorSubject. + * @param defaultValue the initial value, not null (verified) * @since 2.0 */ @SuppressWarnings("unchecked") - BehaviorSubject() { + BehaviorSubject(T defaultValue) { this.lock = new ReentrantReadWriteLock(); this.readLock = lock.readLock(); this.writeLock = lock.writeLock(); - this.subscribers = new AtomicReference<>(EMPTY); - this.value = new AtomicReference<>(); + this.observers = new AtomicReference<>(EMPTY); + this.value = new AtomicReference<>(defaultValue); this.terminalEvent = new AtomicReference<>(); } - /** - * Constructs a BehaviorSubject with the given initial value. - * @param defaultValue the initial value, not null (verified) - * @throws NullPointerException if {@code defaultValue} is {@code null} - * @since 2.0 - */ - BehaviorSubject(T defaultValue) { - this(); - this.value.lazySet(Objects.requireNonNull(defaultValue, "defaultValue is null")); - } - @Override protected void subscribeActual(Observer observer) { BehaviorDisposable bs = new BehaviorDisposable<>(observer, this); @@ -257,7 +249,7 @@ public void onNext(T t) { } Object o = NotificationLite.next(t); setCurrent(o); - for (BehaviorDisposable bs : subscribers.get()) { + for (BehaviorDisposable bs : observers.get()) { bs.emitNext(o, index); } } @@ -289,12 +281,12 @@ public void onComplete() { @Override @CheckReturnValue public boolean hasObservers() { - return subscribers.get().length != 0; + return observers.get().length != 0; } @CheckReturnValue /* test support*/ int subscriberCount() { - return subscribers.get().length; + return observers.get().length; } @Override @@ -350,7 +342,7 @@ public boolean hasValue() { boolean add(BehaviorDisposable rs) { for (;;) { - BehaviorDisposable[] a = subscribers.get(); + BehaviorDisposable[] a = observers.get(); if (a == TERMINATED) { return false; } @@ -359,7 +351,7 @@ boolean add(BehaviorDisposable rs) { BehaviorDisposable[] b = new BehaviorDisposable[len + 1]; System.arraycopy(a, 0, b, 0, len); b[len] = rs; - if (subscribers.compareAndSet(a, b)) { + if (observers.compareAndSet(a, b)) { return true; } } @@ -368,7 +360,7 @@ boolean add(BehaviorDisposable rs) { @SuppressWarnings("unchecked") void remove(BehaviorDisposable rs) { for (;;) { - BehaviorDisposable[] a = subscribers.get(); + BehaviorDisposable[] a = observers.get(); int len = a.length; if (len == 0) { return; @@ -392,7 +384,7 @@ void remove(BehaviorDisposable rs) { System.arraycopy(a, 0, b, 0, j); System.arraycopy(a, j + 1, b, j, len - j - 1); } - if (subscribers.compareAndSet(a, b)) { + if (observers.compareAndSet(a, b)) { return; } } @@ -401,13 +393,9 @@ void remove(BehaviorDisposable rs) { @SuppressWarnings("unchecked") BehaviorDisposable[] terminate(Object terminalValue) { - BehaviorDisposable[] a = subscribers.getAndSet(TERMINATED); - if (a != TERMINATED) { - // either this or atomics with lots of allocation - setCurrent(terminalValue); - } + setCurrent(terminalValue); - return a; + return observers.getAndSet(TERMINATED); } void setCurrent(Object o) { diff --git a/src/main/java/io/reactivex/rxjava3/subjects/CompletableSubject.java b/src/main/java/io/reactivex/rxjava3/subjects/CompletableSubject.java index 9753d276a11..57be7dbced4 100644 --- a/src/main/java/io/reactivex/rxjava3/subjects/CompletableSubject.java +++ b/src/main/java/io/reactivex/rxjava3/subjects/CompletableSubject.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/subjects/MaybeSubject.java b/src/main/java/io/reactivex/rxjava3/subjects/MaybeSubject.java index f06d8c1aae2..39dbb78d9c5 100644 --- a/src/main/java/io/reactivex/rxjava3/subjects/MaybeSubject.java +++ b/src/main/java/io/reactivex/rxjava3/subjects/MaybeSubject.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/subjects/PublishSubject.java b/src/main/java/io/reactivex/rxjava3/subjects/PublishSubject.java index 2c3a8478322..6c2d5ac0336 100644 --- a/src/main/java/io/reactivex/rxjava3/subjects/PublishSubject.java +++ b/src/main/java/io/reactivex/rxjava3/subjects/PublishSubject.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/subjects/ReplaySubject.java b/src/main/java/io/reactivex/rxjava3/subjects/ReplaySubject.java index efad31e6694..e103594ba50 100644 --- a/src/main/java/io/reactivex/rxjava3/subjects/ReplaySubject.java +++ b/src/main/java/io/reactivex/rxjava3/subjects/ReplaySubject.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -177,10 +177,12 @@ public static ReplaySubject create() { * @param capacityHint * the initial buffer capacity * @return the created subject + * @throws IllegalArgumentException if {@code capacityHint} is non-positive */ @CheckReturnValue @NonNull public static ReplaySubject create(int capacityHint) { + ObjectHelper.verifyPositive(capacityHint, "capacityHint"); return new ReplaySubject<>(new UnboundedReplayBuffer<>(capacityHint)); } @@ -203,10 +205,12 @@ public static ReplaySubject create(int capacityHint) { * @param maxSize * the maximum number of buffered items * @return the created subject + * @throws IllegalArgumentException if {@code maxSize} is non-positive */ @CheckReturnValue @NonNull public static ReplaySubject createWithSize(int maxSize) { + ObjectHelper.verifyPositive(maxSize, "maxSize"); return new ReplaySubject<>(new SizeBoundReplayBuffer<>(maxSize)); } @@ -258,10 +262,15 @@ public static ReplaySubject createWithSize(int maxSize) { * @param scheduler * the {@link Scheduler} that provides the current time * @return the created subject + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code maxAge} is non-positive */ @CheckReturnValue @NonNull public static ReplaySubject createWithTime(long maxAge, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { + ObjectHelper.verifyPositive(maxAge, "maxAge"); + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); return new ReplaySubject<>(new SizeAndTimeBoundReplayBuffer<>(Integer.MAX_VALUE, maxAge, unit, scheduler)); } @@ -298,10 +307,16 @@ public static ReplaySubject createWithTime(long maxAge, @NonNull TimeUnit * @param scheduler * the {@link Scheduler} that provides the current time * @return the created subject + * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code maxAge} or {@code maxSize} is non-positive */ @CheckReturnValue @NonNull public static ReplaySubject createWithTimeAndSize(long maxAge, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, int maxSize) { + ObjectHelper.verifyPositive(maxSize, "maxSize"); + ObjectHelper.verifyPositive(maxAge, "maxAge"); + Objects.requireNonNull(unit, "unit is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); return new ReplaySubject<>(new SizeAndTimeBoundReplayBuffer<>(maxSize, maxAge, unit, scheduler)); } @@ -320,15 +335,13 @@ protected void subscribeActual(Observer observer) { ReplayDisposable rs = new ReplayDisposable<>(observer, this); observer.onSubscribe(rs); - if (!rs.cancelled) { - if (add(rs)) { - if (rs.cancelled) { - remove(rs); - return; - } + if (add(rs)) { + if (rs.cancelled) { + remove(rs); + return; } - buffer.replay(rs); } + buffer.replay(rs); } @Override @@ -556,10 +569,8 @@ void remove(ReplayDisposable rs) { @SuppressWarnings("unchecked") ReplayDisposable[] terminate(Object terminalValue) { - if (buffer.compareAndSet(null, terminalValue)) { - return observers.getAndSet(TERMINATED); - } - return TERMINATED; + buffer.compareAndSet(null, terminalValue); + return observers.getAndSet(TERMINATED); } /** @@ -641,12 +652,10 @@ static final class UnboundedReplayBuffer final List buffer; - volatile boolean done; - volatile int size; UnboundedReplayBuffer(int capacityHint) { - this.buffer = new ArrayList<>(ObjectHelper.verifyPositive(capacityHint, "capacityHint")); + this.buffer = new ArrayList<>(capacityHint); } @Override @@ -660,7 +669,6 @@ public void addFinal(Object notificationLite) { buffer.add(notificationLite); trimHead(); size++; - done = true; } @Override @@ -761,20 +769,17 @@ public void replay(ReplayDisposable rs) { Object o = b.get(index); - if (done) { - if (index + 1 == s) { - s = size; - if (index + 1 == s) { - if (NotificationLite.isComplete(o)) { - a.onComplete(); - } else { - a.onError(NotificationLite.getError(o)); - } - rs.index = null; - rs.cancelled = true; - return; - } - } + if (NotificationLite.isComplete(o)) { + a.onComplete(); + rs.index = null; + rs.cancelled = true; + return; + } else + if (NotificationLite.isError(o)) { + a.onError(NotificationLite.getError(o)); + rs.index = null; + rs.cancelled = true; + return; } a.onNext((T)o); @@ -845,10 +850,8 @@ static final class SizeBoundReplayBuffer Node tail; - volatile boolean done; - SizeBoundReplayBuffer(int maxSize) { - this.maxSize = ObjectHelper.verifyPositive(maxSize, "maxSize"); + this.maxSize = maxSize; Node h = new Node<>(null); this.tail = h; this.head = h; @@ -884,7 +887,6 @@ public void addFinal(Object notificationLite) { t.lazySet(n); // releases both the tail and size trimHead(); - done = true; } /** @@ -989,18 +991,17 @@ public void replay(ReplayDisposable rs) { Object o = n.value; - if (done) { - if (n.get() == null) { - - if (NotificationLite.isComplete(o)) { - a.onComplete(); - } else { - a.onError(NotificationLite.getError(o)); - } - rs.index = null; - rs.cancelled = true; - return; - } + if (NotificationLite.isComplete(o)) { + a.onComplete(); + rs.index = null; + rs.cancelled = true; + return; + } else + if (NotificationLite.isError(o)) { + a.onError(NotificationLite.getError(o)); + rs.index = null; + rs.cancelled = true; + return; } a.onNext((T)o); @@ -1058,13 +1059,11 @@ static final class SizeAndTimeBoundReplayBuffer TimedNode tail; - volatile boolean done; - SizeAndTimeBoundReplayBuffer(int maxSize, long maxAge, TimeUnit unit, Scheduler scheduler) { - this.maxSize = ObjectHelper.verifyPositive(maxSize, "maxSize"); - this.maxAge = ObjectHelper.verifyPositive(maxAge, "maxAge"); - this.unit = Objects.requireNonNull(unit, "unit is null"); - this.scheduler = Objects.requireNonNull(scheduler, "scheduler is null"); + this.maxSize = maxSize; + this.maxAge = maxAge; + this.unit = unit; + this.scheduler = scheduler; TimedNode h = new TimedNode<>(null, 0L); this.tail = h; this.head = h; @@ -1086,10 +1085,6 @@ void trim() { break; } TimedNode next = h.get(); - if (next == null) { - head = h; - break; - } if (next.time > limit) { head = h; @@ -1156,8 +1151,6 @@ public void addFinal(Object notificationLite) { size++; t.lazySet(n); // releases both the tail and size trimFinal(); - - done = true; } /** @@ -1269,11 +1262,6 @@ public void replay(ReplayDisposable rs) { for (;;) { - if (rs.cancelled) { - rs.index = null; - return; - } - for (;;) { if (rs.cancelled) { rs.index = null; @@ -1288,18 +1276,17 @@ public void replay(ReplayDisposable rs) { Object o = n.value; - if (done) { - if (n.get() == null) { - - if (NotificationLite.isComplete(o)) { - a.onComplete(); - } else { - a.onError(NotificationLite.getError(o)); - } - rs.index = null; - rs.cancelled = true; - return; - } + if (NotificationLite.isComplete(o)) { + a.onComplete(); + rs.index = null; + rs.cancelled = true; + return; + } else + if (NotificationLite.isError(o)) { + a.onError(NotificationLite.getError(o)); + rs.index = null; + rs.cancelled = true; + return; } a.onNext((T)o); @@ -1307,10 +1294,6 @@ public void replay(ReplayDisposable rs) { index = n; } - if (index.get() != null) { - continue; - } - rs.index = index; missed = rs.addAndGet(-missed); diff --git a/src/main/java/io/reactivex/rxjava3/subjects/SerializedSubject.java b/src/main/java/io/reactivex/rxjava3/subjects/SerializedSubject.java index 137cefc8953..09a45b1da28 100644 --- a/src/main/java/io/reactivex/rxjava3/subjects/SerializedSubject.java +++ b/src/main/java/io/reactivex/rxjava3/subjects/SerializedSubject.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/subjects/SingleSubject.java b/src/main/java/io/reactivex/rxjava3/subjects/SingleSubject.java index 6f8f8b6f353..7559f0329d9 100644 --- a/src/main/java/io/reactivex/rxjava3/subjects/SingleSubject.java +++ b/src/main/java/io/reactivex/rxjava3/subjects/SingleSubject.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/subjects/Subject.java b/src/main/java/io/reactivex/rxjava3/subjects/Subject.java index 35d26d49b51..b76a15da33c 100644 --- a/src/main/java/io/reactivex/rxjava3/subjects/Subject.java +++ b/src/main/java/io/reactivex/rxjava3/subjects/Subject.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/subjects/UnicastSubject.java b/src/main/java/io/reactivex/rxjava3/subjects/UnicastSubject.java index 5e19604eedc..3092dc73c01 100644 --- a/src/main/java/io/reactivex/rxjava3/subjects/UnicastSubject.java +++ b/src/main/java/io/reactivex/rxjava3/subjects/UnicastSubject.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,10 +21,10 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.EmptyDisposable; import io.reactivex.rxjava3.internal.functions.*; -import io.reactivex.rxjava3.internal.fuseable.SimpleQueue; import io.reactivex.rxjava3.internal.observers.BasicIntQueueDisposable; -import io.reactivex.rxjava3.internal.queue.SpscLinkedArrayQueue; import io.reactivex.rxjava3.internal.util.ExceptionHelper; +import io.reactivex.rxjava3.operators.SimpleQueue; +import io.reactivex.rxjava3.operators.SpscLinkedArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; /** @@ -180,7 +180,7 @@ public final class UnicastSubject extends Subject { @CheckReturnValue @NonNull public static UnicastSubject create() { - return create(bufferSize(), Functions.EMPTY_RUNNABLE, true); + return new UnicastSubject<>(bufferSize(), null, true); } /** @@ -188,11 +188,13 @@ public static UnicastSubject create() { * @param the value type * @param capacityHint the hint to size the internal unbounded buffer * @return an UnicastSubject instance + * @throws IllegalArgumentException if {@code capacityHint} is non-positive */ @CheckReturnValue @NonNull public static UnicastSubject create(int capacityHint) { - return create(capacityHint, Functions.EMPTY_RUNNABLE, true); + ObjectHelper.verifyPositive(capacityHint, "capacityHint"); + return new UnicastSubject<>(capacityHint, null, true); } /** @@ -207,11 +209,15 @@ public static UnicastSubject create(int capacityHint) { * @param capacityHint the hint to size the internal unbounded buffer * @param onTerminate the callback to run when the Subject is terminated or cancelled, null not allowed * @return an UnicastSubject instance + * @throws NullPointerException if {@code onTerminate} is {@code null} + * @throws IllegalArgumentException if {@code capacityHint} is non-positive */ @CheckReturnValue @NonNull public static UnicastSubject create(int capacityHint, @NonNull Runnable onTerminate) { - return create(capacityHint, onTerminate, true); + ObjectHelper.verifyPositive(capacityHint, "capacityHint"); + Objects.requireNonNull(onTerminate, "onTerminate"); + return new UnicastSubject<>(capacityHint, onTerminate, true); } /** @@ -227,11 +233,15 @@ public static UnicastSubject create(int capacityHint, @NonNull Runnable o * @param onTerminate the callback to run when the Subject is terminated or cancelled, null not allowed * @param delayError deliver pending onNext events before onError * @return an UnicastSubject instance + * @throws NullPointerException if {@code onTerminate} is {@code null} + * @throws IllegalArgumentException if {@code capacityHint} is non-positive * @since 2.2 */ @CheckReturnValue @NonNull public static UnicastSubject create(int capacityHint, @NonNull Runnable onTerminate, boolean delayError) { + ObjectHelper.verifyPositive(capacityHint, "capacityHint"); + Objects.requireNonNull(onTerminate, "onTerminate"); return new UnicastSubject<>(capacityHint, onTerminate, delayError); } @@ -249,7 +259,7 @@ public static UnicastSubject create(int capacityHint, @NonNull Runnable o @CheckReturnValue @NonNull public static UnicastSubject create(boolean delayError) { - return create(bufferSize(), Functions.EMPTY_RUNNABLE, delayError); + return new UnicastSubject<>(bufferSize(), null, delayError); } /** @@ -262,8 +272,8 @@ public static UnicastSubject create(boolean delayError) { * @since 2.2 */ UnicastSubject(int capacityHint, Runnable onTerminate, boolean delayError) { - this.queue = new SpscLinkedArrayQueue<>(ObjectHelper.verifyPositive(capacityHint, "capacityHint")); - this.onTerminate = new AtomicReference<>(Objects.requireNonNull(onTerminate, "onTerminate")); + this.queue = new SpscLinkedArrayQueue<>(capacityHint); + this.onTerminate = new AtomicReference<>(onTerminate); this.delayError = delayError; this.downstream = new AtomicReference<>(); this.once = new AtomicBoolean(); diff --git a/src/main/java/io/reactivex/rxjava3/subjects/package-info.java b/src/main/java/io/reactivex/rxjava3/subjects/package-info.java index 88fde8391df..a2736d7eee5 100644 --- a/src/main/java/io/reactivex/rxjava3/subjects/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/subjects/package-info.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ /** @@ -21,7 +18,8 @@ *

* Available subject classes with their respective base classes and consumer interfaces: *
- *

The available observer types.
Reactive typeBase interfaceSimpleDisposableResource
{@link io.reactivex.rxjava3.core.Observable Observable}
+ *
+ * * * *
The available subject classes with their respective base classes and consumer interfaces.
Subject typeBase classConsumer interface
{@link io.reactivex.rxjava3.subjects.Subject Subject} diff --git a/src/main/java/io/reactivex/rxjava3/subscribers/DefaultSubscriber.java b/src/main/java/io/reactivex/rxjava3/subscribers/DefaultSubscriber.java index 6a936eb8d97..9f8385b5869 100644 --- a/src/main/java/io/reactivex/rxjava3/subscribers/DefaultSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/subscribers/DefaultSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/subscribers/DisposableSubscriber.java b/src/main/java/io/reactivex/rxjava3/subscribers/DisposableSubscriber.java index 566b0097f79..a3212830182 100644 --- a/src/main/java/io/reactivex/rxjava3/subscribers/DisposableSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/subscribers/DisposableSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/subscribers/ResourceSubscriber.java b/src/main/java/io/reactivex/rxjava3/subscribers/ResourceSubscriber.java index 7d9411048a1..95dccfd2b10 100644 --- a/src/main/java/io/reactivex/rxjava3/subscribers/ResourceSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/subscribers/ResourceSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/main/java/io/reactivex/rxjava3/subscribers/SafeSubscriber.java b/src/main/java/io/reactivex/rxjava3/subscribers/SafeSubscriber.java index 0db19796fa6..f66c34b9b97 100644 --- a/src/main/java/io/reactivex/rxjava3/subscribers/SafeSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/subscribers/SafeSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.subscribers; import org.reactivestreams.*; @@ -27,7 +28,7 @@ * * @param the value type */ -public final class SafeSubscriber implements FlowableSubscriber, Subscription { +public final class SafeSubscriber<@NonNull T> implements FlowableSubscriber, Subscription { /** The actual Subscriber. */ final Subscriber downstream; /** The subscription. */ diff --git a/src/main/java/io/reactivex/rxjava3/subscribers/SerializedSubscriber.java b/src/main/java/io/reactivex/rxjava3/subscribers/SerializedSubscriber.java index 9698d97e210..1ea8b4021a7 100644 --- a/src/main/java/io/reactivex/rxjava3/subscribers/SerializedSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/subscribers/SerializedSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.subscribers; import org.reactivestreams.*; diff --git a/src/main/java/io/reactivex/rxjava3/subscribers/TestSubscriber.java b/src/main/java/io/reactivex/rxjava3/subscribers/TestSubscriber.java index cbc9d103202..1d96e7cfd36 100644 --- a/src/main/java/io/reactivex/rxjava3/subscribers/TestSubscriber.java +++ b/src/main/java/io/reactivex/rxjava3/subscribers/TestSubscriber.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.subscribers; import java.util.concurrent.atomic.*; @@ -179,15 +180,16 @@ public void onError(@NonNull Throwable t) { if (!checkSubscriptionOnce) { checkSubscriptionOnce = true; if (upstream.get() == null) { - errors.add(new NullPointerException("onSubscribe not called in proper order")); + errors.add(new IllegalStateException("onSubscribe not called in proper order")); } } try { lastThread = Thread.currentThread(); - errors.add(t); if (t == null) { - errors.add(new IllegalStateException("onError received a null Throwable")); + errors.add(new NullPointerException("onError received a null Throwable")); + } else { + errors.add(t); } downstream.onError(t); diff --git a/src/main/java/io/reactivex/rxjava3/subscribers/package-info.java b/src/main/java/io/reactivex/rxjava3/subscribers/package-info.java index 348792062ae..592aea185b8 100644 --- a/src/main/java/io/reactivex/rxjava3/subscribers/package-info.java +++ b/src/main/java/io/reactivex/rxjava3/subscribers/package-info.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ /** diff --git a/src/main/module/module-info.java b/src/main/module/module-info.java new file mode 100644 index 00000000000..4bed327f1a7 --- /dev/null +++ b/src/main/module/module-info.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +module io.reactivex.rxjava3 { + exports io.reactivex.rxjava3.annotations; + exports io.reactivex.rxjava3.core; + exports io.reactivex.rxjava3.disposables; + exports io.reactivex.rxjava3.exceptions; + exports io.reactivex.rxjava3.flowables; + exports io.reactivex.rxjava3.functions; + exports io.reactivex.rxjava3.observables; + exports io.reactivex.rxjava3.observers; + exports io.reactivex.rxjava3.operators; + exports io.reactivex.rxjava3.parallel; + exports io.reactivex.rxjava3.plugins; + exports io.reactivex.rxjava3.processors; + exports io.reactivex.rxjava3.schedulers; + exports io.reactivex.rxjava3.subjects; + exports io.reactivex.rxjava3.subscribers; + + requires transitive org.reactivestreams; +} \ No newline at end of file diff --git a/src/test/java/io/reactivex/rxjava3/completable/CapturingUncaughtExceptionHandler.java b/src/test/java/io/reactivex/rxjava3/completable/CapturingUncaughtExceptionHandler.java index 66738a55130..8379925bee4 100644 --- a/src/test/java/io/reactivex/rxjava3/completable/CapturingUncaughtExceptionHandler.java +++ b/src/test/java/io/reactivex/rxjava3/completable/CapturingUncaughtExceptionHandler.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.completable; diff --git a/src/test/java/io/reactivex/rxjava3/completable/CompletableRetryTest.java b/src/test/java/io/reactivex/rxjava3/completable/CompletableRetryTest.java index 909ce356690..3d3ad659688 100644 --- a/src/test/java/io/reactivex/rxjava3/completable/CompletableRetryTest.java +++ b/src/test/java/io/reactivex/rxjava3/completable/CompletableRetryTest.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2017-present, RxJava Contributors. +/* + * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at @@ -20,6 +20,7 @@ import org.junit.Test; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; @@ -113,4 +114,42 @@ public void retryTimesPredicateWithZeroRetries() { assertEquals(1, numberOfSubscribeCalls.get()); } + + @Test + public void untilTrueEmpty() { + Completable.complete() + .retryUntil(() -> true) + .test() + .assertResult(); + } + + @Test + public void untilFalseEmpty() { + Completable.complete() + .retryUntil(() -> false) + .test() + .assertResult(); + } + + @Test + public void untilTrueError() { + Completable.error(new TestException()) + .retryUntil(() -> true) + .test() + .assertFailure(TestException.class); + } + + @Test + public void untilFalseError() { + AtomicInteger counter = new AtomicInteger(); + Completable.defer(() -> { + if (counter.getAndIncrement() == 0) { + return Completable.error(new TestException()); + } + return Completable.complete(); + }) + .retryUntil(() -> false) + .test() + .assertResult(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/completable/CompletableTest.java b/src/test/java/io/reactivex/rxjava3/completable/CompletableTest.java index d319e488610..9f64b81d120 100644 --- a/src/test/java/io/reactivex/rxjava3/completable/CompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/completable/CompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,6 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; @@ -156,11 +155,6 @@ public void complete() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void concatNull() { - Completable.concatArray((Completable[])null); - } - @Test public void concatEmpty() { Completable c = Completable.concatArray(); @@ -214,11 +208,6 @@ public void concatIterableEmpty() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void concatIterableNull() { - Completable.concat((Iterable)null); - } - @Test(expected = NullPointerException.class) public void concatIterableIteratorNull() { Completable c = Completable.concat(new Iterable() { @@ -231,13 +220,6 @@ public Iterator iterator() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void concatIterableWithNull() { - Completable c = Completable.concat(Arrays.asList(normal.completable, (Completable)null)); - - c.blockingAwait(); - } - @Test public void concatIterableSingle() { Completable c = Completable.concat(Collections.singleton(normal.completable)); @@ -367,11 +349,6 @@ public void accept(long v) { Assert.assertEquals(Arrays.asList(5L, 4L, 4L), requested); } - @Test(expected = NullPointerException.class) - public void createNull() { - Completable.unsafeCreate(null); - } - @Test(expected = NullPointerException.class) public void createOnSubscribeThrowsNPE() { Completable c = Completable.unsafeCreate(new CompletableSource() { @@ -424,11 +401,6 @@ public Completable get() { normal.assertSubscriptions(1); } - @Test(expected = NullPointerException.class) - public void deferNull() { - Completable.defer(null); - } - @Test(expected = NullPointerException.class) public void deferReturnsNull() { Completable c = Completable.defer(new Supplier() { @@ -463,11 +435,6 @@ public Completable get() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void errorSupplierNull() { - Completable.error((Supplier)null); - } - @Test(expected = TestException.class) public void errorSupplierNormal() { Completable c = Completable.error(new Supplier() { @@ -502,11 +469,6 @@ public void errorSupplierThrows() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void errorNull() { - Completable.error((Throwable)null); - } - @Test(expected = TestException.class) public void errorNormal() { Completable c = Completable.error(new TestException()); @@ -514,11 +476,6 @@ public void errorNormal() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void fromCallableNull() { - Completable.fromCallable(null); - } - @Test public void fromCallableNormal() { final AtomicInteger calls = new AtomicInteger(); @@ -545,11 +502,6 @@ public void fromCallableThrows() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void fromFlowableNull() { - Completable.fromPublisher(null); - } - @Test public void fromFlowableEmpty() { Completable c = Completable.fromPublisher(Flowable.empty()); @@ -578,11 +530,6 @@ public Throwable get() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void fromObservableNull() { - Completable.fromObservable(null); - } - @Test public void fromObservableEmpty() { Completable c = Completable.fromObservable(Observable.empty()); @@ -611,11 +558,6 @@ public Throwable get() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void fromActionNull() { - Completable.fromAction(null); - } - @Test public void fromActionNormal() { final AtomicInteger calls = new AtomicInteger(); @@ -642,11 +584,6 @@ public void fromActionThrows() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void fromSingleNull() { - Completable.fromSingle(null); - } - @Test public void fromSingleNormal() { Completable c = Completable.fromSingle(Single.just(1)); @@ -666,11 +603,6 @@ public Throwable get() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void mergeNull() { - Completable.mergeArray((Completable[])null); - } - @Test public void mergeEmpty() { Completable c = Completable.mergeArray(); @@ -724,11 +656,6 @@ public void mergeIterableEmpty() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void mergeIterableNull() { - Completable.merge((Iterable)null); - } - @Test(expected = NullPointerException.class) public void mergeIterableIteratorNull() { Completable c = Completable.merge(new Iterable() { @@ -741,13 +668,6 @@ public Iterator iterator() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void mergeIterableWithNull() { - Completable c = Completable.merge(Arrays.asList(normal.completable, (Completable)null)); - - c.blockingAwait(); - } - @Test public void mergeIterableSingle() { Completable c = Completable.merge(Collections.singleton(normal.completable)); @@ -878,11 +798,6 @@ public void accept(long v) { Assert.assertEquals(Arrays.asList(5L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), requested); } - @Test(expected = NullPointerException.class) - public void mergeDelayErrorNull() { - Completable.mergeArrayDelayError((Completable[])null); - } - @Test public void mergeDelayErrorEmpty() { Completable c = Completable.mergeArrayDelayError(); @@ -940,11 +855,6 @@ public void mergeDelayErrorIterableEmpty() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void mergeDelayErrorIterableNull() { - Completable.mergeDelayError((Iterable)null); - } - @Test(expected = NullPointerException.class) public void mergeDelayErrorIterableIteratorNull() { Completable c = Completable.mergeDelayError(new Iterable() { @@ -957,13 +867,6 @@ public Iterator iterator() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void mergeDelayErrorIterableWithNull() { - Completable c = Completable.mergeDelayError(Arrays.asList(normal.completable, (Completable)null)); - - c.blockingAwait(); - } - @Test public void mergeDelayErrorIterableSingle() { Completable c = Completable.mergeDelayError(Collections.singleton(normal.completable)); @@ -1204,16 +1107,6 @@ public void onComplete() { Assert.assertEquals(0, calls.get()); } - @Test(expected = NullPointerException.class) - public void timerUnitNull() { - Completable.timer(1, null); - } - - @Test(expected = NullPointerException.class) - public void timerSchedulerNull() { - Completable.timer(1, TimeUnit.SECONDS, null); - } - @Test public void usingNormalEager() { final AtomicInteger dispose = new AtomicInteger(); @@ -1398,32 +1291,6 @@ public void onComplete() { Assert.assertFalse(complete.get()); } - @Test(expected = NullPointerException.class) - public void usingResourceSupplierNull() { - Completable.using(null, new Function() { - @Override - public Completable apply(Object v) { - return normal.completable; - } - }, new Consumer() { - @Override - public void accept(Object v) { } - }); - } - - @Test(expected = NullPointerException.class) - public void usingMapperNull() { - Completable.using(new Supplier() { - @Override - public Object get() { - return 1; - } - }, null, new Consumer() { - @Override - public void accept(Object v) { } - }); - } - @Test(expected = NullPointerException.class) public void usingMapperReturnsNull() { Completable c = Completable.using(new Supplier() { @@ -1444,21 +1311,6 @@ public void accept(Object v) { } c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void usingDisposeNull() { - Completable.using(new Supplier() { - @Override - public Object get() { - return 1; - } - }, new Function() { - @Override - public Completable apply(Object v) { - return normal.completable; - } - }, null); - } - @Test(expected = TestException.class) public void usingResourceThrows() { Completable c = Completable.using(new Supplier() { @@ -1530,11 +1382,6 @@ public Completable apply(Completable n) { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void composeNull() { - error.completable.compose(null); - } - @Test public void concatWithNormal() { Completable c = normal.completable.concatWith(normal.completable); @@ -1551,21 +1398,6 @@ public void concatWithError() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void concatWithNull() { - normal.completable.concatWith(null); - } - - @Test(expected = NullPointerException.class) - public void delayUnitNull() { - normal.completable.delay(1, null); - } - - @Test(expected = NullPointerException.class) - public void delaySchedulerNull() { - normal.completable.delay(1, TimeUnit.SECONDS, null); - } - @Test public void delayNormal() throws InterruptedException { Completable c = normal.completable.delay(250, TimeUnit.MILLISECONDS); @@ -1712,11 +1544,6 @@ public void run() { Assert.assertEquals(0, calls.get()); } - @Test(expected = NullPointerException.class) - public void doOnCompleteNull() { - normal.completable.doOnComplete(null); - } - @Test(expected = TestException.class) public void doOnCompleteThrows() { Completable c = normal.completable.doOnComplete(new Action() { @@ -1794,11 +1621,6 @@ public void onComplete() { Assert.assertEquals(1, calls.get()); } - @Test(expected = NullPointerException.class) - public void doOnDisposeNull() { - normal.completable.doOnDispose(null); - } - @Test public void doOnDisposeThrows() { List errors = TestHelper.trackPluginErrors(); @@ -1868,11 +1690,6 @@ public void accept(Throwable e) { Assert.assertTrue(err.get() instanceof TestException); } - @Test(expected = NullPointerException.class) - public void doOnErrorNull() { - normal.completable.doOnError(null); - } - @Test public void doOnErrorThrows() { Completable c = error.completable.doOnError(new Consumer() { @@ -1908,11 +1725,6 @@ public void accept(Disposable d) { Assert.assertEquals(10, calls.get()); } - @Test(expected = NullPointerException.class) - public void doOnSubscribeNull() { - normal.completable.doOnSubscribe(null); - } - @Test(expected = TestException.class) public void doOnSubscribeThrows() { Completable c = normal.completable.doOnSubscribe(new Consumer() { @@ -1960,11 +1772,6 @@ public void run() { Assert.assertEquals(1, calls.get()); } - @Test(expected = NullPointerException.class) - public void liftNull() { - normal.completable.lift(null); - } - @Test(expected = NullPointerException.class) public void liftReturnsNull() { Completable c = normal.completable.lift(new CompletableOperator() { @@ -2015,11 +1822,6 @@ public void liftOnErrorComplete() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void mergeWithNull() { - normal.completable.mergeWith(null); - } - @Test public void mergeWithNormal() { Completable c = normal.completable.mergeWith(normal.completable); @@ -2029,11 +1831,6 @@ public void mergeWithNormal() { normal.assertSubscriptions(2); } - @Test(expected = NullPointerException.class) - public void observeOnNull() { - normal.completable.observeOn(null); - } - @Test public void observeOnNormal() throws InterruptedException { final AtomicReference name = new AtomicReference<>(); @@ -2120,16 +1917,6 @@ public boolean test(Throwable e) { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void onErrorCompleteNull() { - error.completable.onErrorComplete(null); - } - - @Test(expected = NullPointerException.class) - public void onErrorResumeNextNull() { - error.completable.onErrorResumeNext(null); - } - @Test public void onErrorResumeNextFunctionReturnsNull() { Completable c = error.completable.onErrorResumeNext(new Function() { @@ -2314,16 +2101,6 @@ public boolean getAsBoolean() { Assert.assertEquals(5, calls.get()); } - @Test(expected = NullPointerException.class) - public void repeatUntilNull() { - normal.completable.repeatUntil(null); - } - - @Test(expected = NullPointerException.class) - public void repeatWhenNull() { - normal.completable.repeatWhen(null); - } - @Test public void retryNormal() { Completable c = normal.completable.retry(); @@ -2402,11 +2179,6 @@ public boolean test(Throwable e) { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void retryPredicateNull() { - error.completable.retry((Predicate)null); - } - @Test public void retryPredicate5Times() { final AtomicInteger calls = new AtomicInteger(5); @@ -2538,22 +2310,6 @@ public void accept(Throwable e) { Assert.assertFalse("Not completed", complete.get()); } - @Test(expected = NullPointerException.class) - public void subscribeTwoCallbacksFirstNull() { - normal.completable.subscribe(new Action() { - @Override - public void run() { } - }, null); - } - - @Test(expected = NullPointerException.class) - public void subscribeTwoCallbacksSecondNull() { - normal.completable.subscribe(new Action() { - @Override - public void run() { } - }, null); - } - @Test public void subscribeTwoCallbacksCompleteThrows() { List errors = TestHelper.trackPluginErrors(); @@ -2651,26 +2407,6 @@ public void run() { } } - @Test(expected = NullPointerException.class) - public void subscribeActionNull() { - normal.completable.subscribe((Action)null); - } - - @Test(expected = NullPointerException.class) - public void subscribeSubscriberNull() { - normal.completable.toFlowable().subscribe((Subscriber)null); - } - - @Test(expected = NullPointerException.class) - public void subscribeObserverNull() { - normal.completable.toObservable().subscribe((Observer)null); - } - - @Test(expected = NullPointerException.class) - public void subscribeCompletableSubscriberNull() { - normal.completable.subscribe((CompletableObserver)null); - } - @Test public void subscribeSubscriberNormal() { TestSubscriber ts = new TestSubscriber<>(); @@ -2693,11 +2429,6 @@ public void subscribeSubscriberError() { ts.assertError(TestException.class); } - @Test(expected = NullPointerException.class) - public void subscribeOnNull() { - normal.completable.subscribeOn(null); - } - @Test public void subscribeOnNormal() { final AtomicReference name = new AtomicReference<>(); @@ -2763,21 +2494,6 @@ public Object call() throws Exception { normal.assertSubscriptions(0); } - @Test(expected = NullPointerException.class) - public void timeoutUnitNull() { - normal.completable.timeout(1, null); - } - - @Test(expected = NullPointerException.class) - public void timeoutSchedulerNull() { - normal.completable.timeout(1, TimeUnit.SECONDS, (Scheduler)null); - } - - @Test(expected = NullPointerException.class) - public void timeoutOtherNull() { - normal.completable.timeout(1, TimeUnit.SECONDS, (Completable)null); - } - @Test public void toNormal() { normal.completable @@ -2818,11 +2534,6 @@ public Flowable apply(Completable v) { .assertComplete(); } - @Test(expected = NullPointerException.class) - public void toNull() { - normal.completable.to(null); - } - @Test public void toFlowableNormal() { normal.completable.toFlowable().blockingForEach(Functions.emptyConsumer()); @@ -2863,11 +2574,6 @@ public Object get() { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void toSingleSupplierNull() { - normal.completable.toSingle(null); - } - @Test(expected = NullPointerException.class) public void toSingleSupplierReturnsNull() { normal.completable.toSingle(new Supplier() { @@ -2896,11 +2602,6 @@ public void toSingleDefaultNormal() { Assert.assertEquals((Integer)1, normal.completable.toSingleDefault(1).blockingGet()); } - @Test(expected = NullPointerException.class) - public void toSingleDefaultNull() { - normal.completable.toSingleDefault(null); - } - @Test public void unsubscribeOnNormal() throws InterruptedException { final AtomicReference name = new AtomicReference<>(); @@ -2942,11 +2643,6 @@ public void onComplete() { Assert.assertTrue(name.get().startsWith("RxComputation")); } - @Test(expected = NullPointerException.class) - public void ambArrayNull() { - Completable.ambArray((Completable[])null); - } - @Test public void ambArrayEmpty() { Completable c = Completable.ambArray(); @@ -3106,11 +2802,6 @@ public void ambIterableEmpty() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void ambIterableNull() { - Completable.amb((Iterable)null); - } - @Test public void ambIterableIteratorNull() { Completable.amb(new Iterable() { @@ -3184,11 +2875,6 @@ public void ambIterableIteratorNextThrows() { .assertError(TestException.class); } - @Test(expected = NullPointerException.class) - public void ambWithNull() { - normal.completable.ambWith(null); - } - @Test public void ambWithArrayOneFires() { PublishProcessor pp1 = PublishProcessor.create(); @@ -3424,21 +3110,6 @@ public void startWithObservableError() { to.assertNotComplete(); } - @Test(expected = NullPointerException.class) - public void startWithCompletableNull() { - normal.completable.startWith((Completable)null); - } - - @Test(expected = NullPointerException.class) - public void startWithFlowableNull() { - normal.completable.startWith((Flowable)null); - } - - @Test(expected = NullPointerException.class) - public void startWithObservableNull() { - normal.completable.startWith((Observable)null); - } - @Test public void andThen() { TestSubscriber ts = new TestSubscriber<>(0); @@ -3830,11 +3501,6 @@ public void run() { Assert.assertEquals(0, calls.get()); } - @Test(expected = NullPointerException.class) - public void doOnCompletedNull() { - normal.completable.doOnComplete(null); - } - @Test(expected = TestException.class) public void doOnCompletedThrows() { Completable c = normal.completable.doOnComplete(new Action() { @@ -3901,11 +3567,6 @@ public void run() { Assert.assertTrue("Closure not called", doneAfter.get()); } - @Test(expected = NullPointerException.class) - public void doAfterTerminateNull() { - normal.completable.doAfterTerminate(null); - } - @Test public void subscribeEmptyOnError() { expectUncaughtTestException(new Action() { @@ -3939,16 +3600,6 @@ public void run() { }); } - @Test(expected = NullPointerException.class) - public void andThenCompletableNull() { - normal.completable.andThen((Completable)null); - } - - @Test(expected = NullPointerException.class) - public void andThenFlowableNull() { - normal.completable.andThen((Observable)null); - } - @Test public void andThenCompletableNormal() { final AtomicBoolean run = new AtomicBoolean(); @@ -4286,11 +3937,6 @@ public void andThenSingle() { ts.assertNoErrors(); } - @Test(expected = NullPointerException.class) - public void fromFutureNull() { - Completable.fromFuture(null); - } - @Test public void fromFutureNormal() { ExecutorService exec = Executors.newSingleThreadExecutor(); @@ -4333,11 +3979,6 @@ public void run() { } } - @Test(expected = NullPointerException.class) - public void fromRunnableNull() { - Completable.fromRunnable(null); - } - @Test public void fromRunnableNormal() { final AtomicInteger calls = new AtomicInteger(); @@ -4364,41 +4005,6 @@ public void fromRunnableThrows() { c.blockingAwait(); } - @Test(expected = NullPointerException.class) - public void doOnErrorNullValue() { - Completable.complete().doOnError(null); - } - - @Test(expected = NullPointerException.class) - public void doOnSubscribeNullValue() { - Completable.complete().doOnSubscribe(null); - } - - @Test(expected = NullPointerException.class) - public void doAfterTerminateNullValue() { - Completable.complete().doAfterTerminate(null); - } - - @Test(expected = NullPointerException.class) - public void doOnTerminateNullValue() { - Completable.complete().doOnTerminate(null); - } - - @Test(expected = NullPointerException.class) - public void doOnCompleteNullValue() { - Completable.complete().doOnComplete(null); - } - - @Test(expected = NullPointerException.class) - public void doOnDisposeNullValue() { - Completable.complete().doOnDispose(null); - } - - @Test(expected = NullPointerException.class) - public void doOnEventNullValue() { - Completable.complete().doOnEvent(null); - } - @Test public void doOnEventComplete() { final AtomicInteger atomicInteger = new AtomicInteger(0); diff --git a/src/test/java/io/reactivex/rxjava3/completable/CompletableTimerTest.java b/src/test/java/io/reactivex/rxjava3/completable/CompletableTimerTest.java index 17f1e7beaef..cad1780eb6a 100644 --- a/src/test/java/io/reactivex/rxjava3/completable/CompletableTimerTest.java +++ b/src/test/java/io/reactivex/rxjava3/completable/CompletableTimerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/core/BackpressureEnumTest.java b/src/test/java/io/reactivex/rxjava3/core/BackpressureEnumTest.java index 583899167db..e007bfe8ef1 100644 --- a/src/test/java/io/reactivex/rxjava3/core/BackpressureEnumTest.java +++ b/src/test/java/io/reactivex/rxjava3/core/BackpressureEnumTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.core; import static org.junit.Assert.*; diff --git a/src/test/java/io/reactivex/rxjava3/core/ConverterTest.java b/src/test/java/io/reactivex/rxjava3/core/ConverterTest.java index 68006e3c643..1d0ddd5e40b 100644 --- a/src/test/java/io/reactivex/rxjava3/core/ConverterTest.java +++ b/src/test/java/io/reactivex/rxjava3/core/ConverterTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/core/DisposeTaskTest.java b/src/test/java/io/reactivex/rxjava3/core/DisposeTaskTest.java new file mode 100644 index 00000000000..d429b588f73 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/core/DisposeTaskTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.core; + +import static org.junit.Assert.fail; +import static org.testng.Assert.assertTrue; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Scheduler.DisposeTask; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class DisposeTaskTest extends RxJavaTest { + + @Test + public void runnableThrows() throws Throwable { + TestHelper.withErrorTracking(errors -> { + + Scheduler.Worker worker = Schedulers.single().createWorker(); + + DisposeTask task = new DisposeTask(() -> { + throw new TestException(); + }, worker); + + try { + task.run(); + fail("Should have thrown!"); + } catch (TestException expected) { + // expected + } + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + assertTrue(worker.isDisposed()); + }); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/core/NotificationTest.java b/src/test/java/io/reactivex/rxjava3/core/NotificationTest.java index 1c1a6adf597..b26262c15c7 100644 --- a/src/test/java/io/reactivex/rxjava3/core/NotificationTest.java +++ b/src/test/java/io/reactivex/rxjava3/core/NotificationTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -42,10 +42,21 @@ public void valueOfOnCompleteIsNull() { public void notEqualsToObject() { Notification n1 = Notification.createOnNext(0); assertNotEquals(0, n1); + assertNotEquals(n1, 0); Notification n2 = Notification.createOnError(new TestException()); assertNotEquals(0, n2); + assertNotEquals(n2, 0); Notification n3 = Notification.createOnComplete(); assertNotEquals(0, n3); + assertNotEquals(n3, 0); + } + + @Test + public void twoEqual() { + Notification n1 = Notification.createOnNext(0); + Notification n2 = Notification.createOnNext(0); + assertEquals(n1, n2); + assertEquals(n2, n1); } @Test diff --git a/src/test/java/io/reactivex/rxjava3/core/PeriodicDirectTaskTest.java b/src/test/java/io/reactivex/rxjava3/core/PeriodicDirectTaskTest.java new file mode 100644 index 00000000000..077171acdb9 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/core/PeriodicDirectTaskTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.core; + +import static org.junit.Assert.fail; +import static org.testng.Assert.assertTrue; + +import java.util.List; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Scheduler.PeriodicDirectTask; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class PeriodicDirectTaskTest extends RxJavaTest { + + @Test + public void runnableThrows() { + List errors = TestHelper.trackPluginErrors(); + try { + Scheduler.Worker worker = Schedulers.single().createWorker(); + + PeriodicDirectTask task = new PeriodicDirectTask(() -> { + throw new TestException(); + }, worker); + + try { + task.run(); + fail("Should have thrown!"); + } catch (TestException expected) { + // expected + } + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + assertTrue(worker.isDisposed()); + + task.run(); + } finally { + RxJavaPlugins.reset(); + } + } +} diff --git a/src/test/java/io/reactivex/rxjava3/core/Retry.java b/src/test/java/io/reactivex/rxjava3/core/Retry.java index a738e0e3c78..5d543afb1c2 100644 --- a/src/test/java/io/reactivex/rxjava3/core/Retry.java +++ b/src/test/java/io/reactivex/rxjava3/core/Retry.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -75,4 +75,4 @@ public Statement apply(Statement base, Description description) { private Statement statement(final Statement base, final Description description) { return new RetryStatement(base, description); } -} \ No newline at end of file +} diff --git a/src/test/java/io/reactivex/rxjava3/core/RxJavaTest.java b/src/test/java/io/reactivex/rxjava3/core/RxJavaTest.java index d903a87f0c9..1e6d9fd33d6 100644 --- a/src/test/java/io/reactivex/rxjava3/core/RxJavaTest.java +++ b/src/test/java/io/reactivex/rxjava3/core/RxJavaTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.core; import java.util.concurrent.TimeUnit; @@ -20,9 +18,13 @@ import org.junit.*; import org.junit.rules.Timeout; +import io.reactivex.rxjava3.testsupport.SuppressUndeliverableRule; + public abstract class RxJavaTest { @Rule public Timeout globalTimeout = new Timeout(5, TimeUnit.MINUTES); + @Rule + public final SuppressUndeliverableRule suppressUndeliverableRule = new SuppressUndeliverableRule(); /** * Announce creates a log print preventing Travis CI from killing the build. diff --git a/src/test/java/io/reactivex/rxjava3/core/SchedulerTest.java b/src/test/java/io/reactivex/rxjava3/core/SchedulerTest.java new file mode 100644 index 00000000000..bbb36f15948 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/core/SchedulerTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.core; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.After; +import org.junit.Test; + +import java.util.concurrent.TimeUnit; + +public class SchedulerTest { + private static final String DRIFT_USE_NANOTIME = "rx3.scheduler.use-nanotime"; + + @After + public void cleanup() { + // reset value to default in order to not influence other tests + Scheduler.IS_DRIFT_USE_NANOTIME = false; + } + + @Test + public void driftUseNanoTimeNotSetByDefault() { + assertFalse(Scheduler.IS_DRIFT_USE_NANOTIME); + assertFalse(Boolean.getBoolean(DRIFT_USE_NANOTIME)); + } + + @Test + public void computeNow_currentTimeMillis() { + TimeUnit unit = TimeUnit.MILLISECONDS; + assertTrue(isInRange(System.currentTimeMillis(), Scheduler.computeNow(unit), unit, 250, TimeUnit.MILLISECONDS)); + } + + @Test + public void computeNow_nanoTime() { + TimeUnit unit = TimeUnit.NANOSECONDS; + Scheduler.IS_DRIFT_USE_NANOTIME = true; + + assertFalse(isInRange(System.currentTimeMillis(), Scheduler.computeNow(unit), unit, 250, TimeUnit.MILLISECONDS)); + assertTrue(isInRange(System.nanoTime(), Scheduler.computeNow(unit), TimeUnit.NANOSECONDS, 250, TimeUnit.MILLISECONDS)); + } + + private boolean isInRange(long start, long stop, TimeUnit source, long maxDiff, TimeUnit diffUnit) { + long diff = Math.abs(stop - start); + return diffUnit.convert(diff, source) <= maxDiff; + } + + @Test + public void clockDriftCalculation() { + assertEquals(100_000_000L, Scheduler.computeClockDrift(100, "milliseconds")); + + assertEquals(2_000_000_000L, Scheduler.computeClockDrift(2, "seconds")); + + assertEquals(180_000_000_000L, Scheduler.computeClockDrift(3, "minutes")); + + assertEquals(240_000_000_000L, Scheduler.computeClockDrift(4, "random")); + + assertEquals(300_000_000_000L, Scheduler.computeClockDrift(5, null)); + } + +} diff --git a/src/test/java/io/reactivex/rxjava3/core/TransformerTest.java b/src/test/java/io/reactivex/rxjava3/core/TransformerTest.java index 20725c80fa6..c672196b605 100644 --- a/src/test/java/io/reactivex/rxjava3/core/TransformerTest.java +++ b/src/test/java/io/reactivex/rxjava3/core/TransformerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/core/XFlatMapTest.java b/src/test/java/io/reactivex/rxjava3/core/XFlatMapTest.java index 7efeee401db..16ebfcb9a37 100644 --- a/src/test/java/io/reactivex/rxjava3/core/XFlatMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/core/XFlatMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ import org.reactivestreams.Publisher; import io.reactivex.rxjava3.exceptions.TestException; -import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.Schedulers; @@ -224,7 +224,7 @@ public Completable apply(Integer v) throws Exception { } @Test - public void observableFlowable() throws Exception { + public void observableObservable() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Observable.just(1) @@ -504,8 +504,213 @@ public Completable apply(Integer v) throws Exception { } } + @Test + public void singlePublisher() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + TestSubscriber ts = Single.just(1) + .subscribeOn(Schedulers.io()) + .flatMapPublisher(new Function>() { + @Override + public Publisher apply(Integer v) throws Exception { + sleep(); + return Flowable.error(new TestException()); + } + }) + .test(); + + cb.await(); + + beforeCancelSleep(ts); + + ts.cancel(); + + Thread.sleep(SLEEP_AFTER_CANCEL); + + ts.assertEmpty(); + + assertTrue(errors.toString(), errors.isEmpty()); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void singleCombiner() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + TestObserver to = Single.just(1) + .subscribeOn(Schedulers.io()) + .flatMap(new Function>() { + @Override + public Single apply(Integer v) throws Exception { + sleep(); + return Single.error(new TestException()); + } + }, (a, b) -> a + b) + .test(); + + cb.await(); + + beforeCancelSleep(to); + + to.dispose(); + + Thread.sleep(SLEEP_AFTER_CANCEL); + + to.assertEmpty(); + + assertTrue(errors.toString(), errors.isEmpty()); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void singleObservable() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + TestObserver to = Single.just(1) + .subscribeOn(Schedulers.io()) + .flatMapObservable(new Function>() { + @Override + public Observable apply(Integer v) throws Exception { + sleep(); + return Observable.error(new TestException()); + } + }) + .test(); + + cb.await(); + + beforeCancelSleep(to); + + to.dispose(); + + Thread.sleep(SLEEP_AFTER_CANCEL); + + to.assertEmpty(); + + assertTrue(errors.toString(), errors.isEmpty()); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void singleNotificationSuccess() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + TestObserver to = Single.just(1) + .subscribeOn(Schedulers.io()) + .flatMap( + new Function>() { + @Override + public Single apply(Integer v) throws Exception { + sleep(); + return Single.error(new TestException()); + } + }, + new Function>() { + @Override + public Single apply(Throwable v) throws Exception { + sleep(); + return Single.error(new TestException()); + } + } + ) + .test(); + + cb.await(); + + beforeCancelSleep(to); + + to.dispose(); + + Thread.sleep(SLEEP_AFTER_CANCEL); + + to.assertEmpty(); + + assertTrue(errors.toString(), errors.isEmpty()); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void singleNotificationError() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + TestObserver to = Single.error(new TestException()) + .subscribeOn(Schedulers.io()) + .flatMap( + new Function>() { + @Override + public Single apply(Integer v) throws Exception { + sleep(); + return Single.error(new TestException()); + } + }, + new Function>() { + @Override + public Single apply(Throwable v) throws Exception { + sleep(); + return Single.error(new TestException()); + } + } + ) + .test(); + + cb.await(); + + beforeCancelSleep(to); + + to.dispose(); + + Thread.sleep(SLEEP_AFTER_CANCEL); + + to.assertEmpty(); + + assertTrue(errors.toString(), errors.isEmpty()); + } finally { + RxJavaPlugins.reset(); + } + } + @Test public void maybeSingle() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + TestObserver to = Maybe.just(1) + .subscribeOn(Schedulers.io()) + .flatMapSingle(new Function>() { + @Override + public Single apply(Integer v) throws Exception { + sleep(); + return Single.error(new TestException()); + } + }) + .toSingle() + .test(); + + cb.await(); + + beforeCancelSleep(to); + + to.dispose(); + + Thread.sleep(SLEEP_AFTER_CANCEL); + + to.assertEmpty(); + + assertTrue(errors.toString(), errors.isEmpty()); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void maybeSingle2() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Maybe.just(1) @@ -566,6 +771,240 @@ public Maybe apply(Integer v) throws Exception { } } + @Test + public void maybePublisher() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + TestSubscriber ts = Maybe.just(1) + .subscribeOn(Schedulers.io()) + .flatMapPublisher(new Function>() { + @Override + public Publisher apply(Integer v) throws Exception { + sleep(); + return Flowable.error(new TestException()); + } + }) + .test(); + + cb.await(); + + beforeCancelSleep(ts); + + ts.cancel(); + + Thread.sleep(SLEEP_AFTER_CANCEL); + + ts.assertEmpty(); + + assertTrue(errors.toString(), errors.isEmpty()); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void maybeObservable() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + TestObserver to = Maybe.just(1) + .subscribeOn(Schedulers.io()) + .flatMapObservable(new Function>() { + @Override + public Observable apply(Integer v) throws Exception { + sleep(); + return Observable.error(new TestException()); + } + }) + .test(); + + cb.await(); + + beforeCancelSleep(to); + + to.dispose(); + + Thread.sleep(SLEEP_AFTER_CANCEL); + + to.assertEmpty(); + + assertTrue(errors.toString(), errors.isEmpty()); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void maybeNotificationSuccess() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + TestObserver to = Maybe.just(1) + .subscribeOn(Schedulers.io()) + .flatMap( + new Function>() { + @Override + public Maybe apply(Integer v) throws Exception { + sleep(); + return Maybe.error(new TestException()); + } + }, + new Function>() { + @Override + public Maybe apply(Throwable v) throws Exception { + sleep(); + return Maybe.error(new TestException()); + } + }, + new Supplier>() { + @Override + public Maybe get() throws Exception { + sleep(); + return Maybe.error(new TestException()); + } + } + ) + .test(); + + cb.await(); + + beforeCancelSleep(to); + + to.dispose(); + + Thread.sleep(SLEEP_AFTER_CANCEL); + + to.assertEmpty(); + + assertTrue(errors.toString(), errors.isEmpty()); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void maybeNotificationError() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + TestObserver to = Maybe.error(new TestException()) + .subscribeOn(Schedulers.io()) + .flatMap( + new Function>() { + @Override + public Maybe apply(Integer v) throws Exception { + sleep(); + return Maybe.error(new TestException()); + } + }, + new Function>() { + @Override + public Maybe apply(Throwable v) throws Exception { + sleep(); + return Maybe.error(new TestException()); + } + }, + new Supplier>() { + @Override + public Maybe get() throws Exception { + sleep(); + return Maybe.error(new TestException()); + } + } + ) + .test(); + + cb.await(); + + beforeCancelSleep(to); + + to.dispose(); + + Thread.sleep(SLEEP_AFTER_CANCEL); + + to.assertEmpty(); + + assertTrue(errors.toString(), errors.isEmpty()); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void maybeNotificationEmpty() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + TestObserver to = Maybe.empty() + .subscribeOn(Schedulers.io()) + .flatMap( + new Function>() { + @Override + public Maybe apply(Integer v) throws Exception { + sleep(); + return Maybe.error(new TestException()); + } + }, + new Function>() { + @Override + public Maybe apply(Throwable v) throws Exception { + sleep(); + return Maybe.error(new TestException()); + } + }, + new Supplier>() { + @Override + public Maybe get() throws Exception { + sleep(); + return Maybe.error(new TestException()); + } + } + ) + .test(); + + cb.await(); + + beforeCancelSleep(to); + + to.dispose(); + + Thread.sleep(SLEEP_AFTER_CANCEL); + + to.assertEmpty(); + + assertTrue(errors.toString(), errors.isEmpty()); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void maybeCombiner() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + TestObserver to = Maybe.just(1) + .subscribeOn(Schedulers.io()) + .flatMap(new Function>() { + @Override + public Maybe apply(Integer v) throws Exception { + sleep(); + return Maybe.error(new TestException()); + } + }, (a, b) -> a + b) + .test(); + + cb.await(); + + beforeCancelSleep(to); + + to.dispose(); + + Thread.sleep(SLEEP_AFTER_CANCEL); + + to.assertEmpty(); + + assertTrue(errors.toString(), errors.isEmpty()); + } finally { + RxJavaPlugins.reset(); + } + } + @Test public void maybeCompletable() throws Exception { List errors = TestHelper.trackPluginErrors(); diff --git a/src/test/java/io/reactivex/rxjava3/disposables/CompositeDisposableTest.java b/src/test/java/io/reactivex/rxjava3/disposables/CompositeDisposableTest.java index 73d605c2ccf..3f76d283d7f 100644 --- a/src/test/java/io/reactivex/rxjava3/disposables/CompositeDisposableTest.java +++ b/src/test/java/io/reactivex/rxjava3/disposables/CompositeDisposableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -290,7 +290,7 @@ public void tryRemoveIfNotIn() { cd.remove(cd1); cd.add(cd2); - cd.remove(cd1); // try removing agian + cd.remove(cd1); // try removing again } @Test(expected = NullPointerException.class) diff --git a/src/test/java/io/reactivex/rxjava3/disposables/DisposableTest.java b/src/test/java/io/reactivex/rxjava3/disposables/DisposableTest.java index b966a1db0f6..e541d404da7 100644 --- a/src/test/java/io/reactivex/rxjava3/disposables/DisposableTest.java +++ b/src/test/java/io/reactivex/rxjava3/disposables/DisposableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/disposables/FutureDisposableTest.java b/src/test/java/io/reactivex/rxjava3/disposables/FutureDisposableTest.java index 3ae97dd3064..544e39ad1b6 100644 --- a/src/test/java/io/reactivex/rxjava3/disposables/FutureDisposableTest.java +++ b/src/test/java/io/reactivex/rxjava3/disposables/FutureDisposableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/disposables/SequentialDisposableTest.java b/src/test/java/io/reactivex/rxjava3/disposables/SequentialDisposableTest.java index 62248db45eb..30663433013 100644 --- a/src/test/java/io/reactivex/rxjava3/disposables/SequentialDisposableTest.java +++ b/src/test/java/io/reactivex/rxjava3/disposables/SequentialDisposableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/disposables/SerialDisposableTests.java b/src/test/java/io/reactivex/rxjava3/disposables/SerialDisposableTests.java index aa53f2ecb05..3a2e73582bd 100644 --- a/src/test/java/io/reactivex/rxjava3/disposables/SerialDisposableTests.java +++ b/src/test/java/io/reactivex/rxjava3/disposables/SerialDisposableTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/exceptions/CompositeExceptionTest.java b/src/test/java/io/reactivex/rxjava3/exceptions/CompositeExceptionTest.java index 331a7dce9c0..cc34f62b899 100644 --- a/src/test/java/io/reactivex/rxjava3/exceptions/CompositeExceptionTest.java +++ b/src/test/java/io/reactivex/rxjava3/exceptions/CompositeExceptionTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.exceptions; import static org.junit.Assert.*; @@ -150,7 +148,7 @@ public void compositeExceptionFromTwoDuplicateComposites() { cex.getCause().printStackTrace(); } - /** + /* * This hijacks the Throwable.printStackTrace() output and puts it in a string, where we can look for * "CIRCULAR REFERENCE" (a String added by Throwable.printEnclosedStackTrace) */ diff --git a/src/test/java/io/reactivex/rxjava3/exceptions/ExceptionsTest.java b/src/test/java/io/reactivex/rxjava3/exceptions/ExceptionsTest.java index 3d2e1eeec4a..b6aa0690100 100644 --- a/src/test/java/io/reactivex/rxjava3/exceptions/ExceptionsTest.java +++ b/src/test/java/io/reactivex/rxjava3/exceptions/ExceptionsTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.exceptions; import static org.junit.Assert.*; diff --git a/src/test/java/io/reactivex/rxjava3/exceptions/OnErrorNotImplementedExceptionTest.java b/src/test/java/io/reactivex/rxjava3/exceptions/OnErrorNotImplementedExceptionTest.java index b8a78de7dcb..70ba775bc11 100644 --- a/src/test/java/io/reactivex/rxjava3/exceptions/OnErrorNotImplementedExceptionTest.java +++ b/src/test/java/io/reactivex/rxjava3/exceptions/OnErrorNotImplementedExceptionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/exceptions/TestException.java b/src/test/java/io/reactivex/rxjava3/exceptions/TestException.java index 8618c7df5e3..7bcdd318fd8 100644 --- a/src/test/java/io/reactivex/rxjava3/exceptions/TestException.java +++ b/src/test/java/io/reactivex/rxjava3/exceptions/TestException.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,7 +14,7 @@ package io.reactivex.rxjava3.exceptions; /** - * Exception for testing if unchecked expections propagate as-is without confusing with + * Exception for testing if unchecked exceptions propagate as-is without confusing with * other type of common exceptions. */ public final class TestException extends RuntimeException { diff --git a/src/test/java/io/reactivex/rxjava3/flowable/Burst.java b/src/test/java/io/reactivex/rxjava3/flowable/Burst.java index 791ec79a2f5..efa0993042a 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/Burst.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/Burst.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.flowable; import java.util.*; diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableBackpressureTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableBackpressureTests.java index 7d0687dd723..e6b3a02c684 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableBackpressureTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableBackpressureTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,7 +24,7 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.exceptions.MissingBackpressureException; +import io.reactivex.rxjava3.exceptions.QueueOverflowException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; import io.reactivex.rxjava3.internal.util.BackpressureHelper; @@ -132,7 +132,7 @@ public void mergeSync() { assertEquals(num, ts.values().size()); // either one can starve the other, but neither should be capable of doing more than 5 batches (taking 4.1) // TODO is it possible to make this deterministic rather than one possibly starving the other? - // benjchristensen => In general I'd say it's not worth trying to make it so, as "fair" algoritms generally take a performance hit + // benjchristensen => In general I'd say it's not worth trying to make it so, as "fair" algorithms generally take a performance hit assertTrue(c1.get() < Flowable.bufferSize() * 5); assertTrue(c2.get() < Flowable.bufferSize() * 5); } @@ -154,7 +154,7 @@ public void mergeAsync() { assertEquals(num, ts.values().size()); // either one can starve the other, but neither should be capable of doing more than 5 batches (taking 4.1) // TODO is it possible to make this deterministic rather than one possibly starving the other? - // benjchristensen => In general I'd say it's not worth trying to make it so, as "fair" algoritms generally take a performance hit + // benjchristensen => In general I'd say it's not worth trying to make it so, as "fair" algorithms generally take a performance hit int max = Flowable.bufferSize() * 7; assertTrue("" + c1.get() + " >= " + max, c1.get() < max); assertTrue("" + c2.get() + " >= " + max, c2.get() < max); @@ -206,7 +206,7 @@ public void mergeAsyncThenObserveOn() { assertEquals(num, ts.values().size()); // either one can starve the other, but neither should be capable of doing more than 5 batches (taking 4.1) // TODO is it possible to make this deterministic rather than one possibly starving the other? - // benjchristensen => In general I'd say it's not worth trying to make it so, as "fair" algoritms generally take a performance hit + // benjchristensen => In general I'd say it's not worth trying to make it so, as "fair" algorithms generally take a performance hit // akarnokd => run this in a loop over 10k times and never saw values get as high as 7*SIZE, but since observeOn delays the unsubscription non-deterministically, the test will remain unreliable assertTrue(c1.get() < Flowable.bufferSize() * 7); assertTrue(c2.get() < Flowable.bufferSize() * 7); @@ -475,7 +475,7 @@ public Integer apply(Integer v) { int vc = ts.values().size(); assertTrue("10 < " + vc, vc <= 10); - ts.assertError(MissingBackpressureException.class); + ts.assertError(QueueOverflowException.class); } @Test diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableCollectTest.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableCollectTest.java index ea93877cdcf..70779959829 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableCollectTest.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableCollectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableCombineLatestTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableCombineLatestTests.java index 3adac790ae0..107c5e583f4 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableCombineLatestTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableCombineLatestTests.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.flowable; import org.junit.Test; diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableConcatTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableConcatTests.java index 5d54f9df5f3..5efb4195e62 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableConcatTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableConcatTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.flowable; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableConversionTest.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableConversionTest.java index a579a82ae70..7079f833f2a 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableConversionTest.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableConversionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableCovarianceTest.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableCovarianceTest.java index ae50092ce9e..9d7ca31319b 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableCovarianceTest.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableCovarianceTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.flowable; diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableDoAfterNextTest.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableDoAfterNextTest.java index 58f21b10d31..eb6878edbdf 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableDoAfterNextTest.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableDoAfterNextTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.flowable; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableDoOnTest.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableDoOnTest.java index b1b12c55772..f4ff588d53f 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableDoOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableDoOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableErrorHandlingTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableErrorHandlingTests.java index df123ee3044..e15c7a1dec8 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableErrorHandlingTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableErrorHandlingTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableEventStream.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableEventStream.java index 861d67c68d0..2428d6cb049 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableEventStream.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableEventStream.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableEventStreamTest.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableEventStreamTest.java index 8965376b8ad..dd38b88afce 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableEventStreamTest.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableEventStreamTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.flowable; diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableFuseableTest.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableFuseableTest.java index 02fa0e5be70..7bf54e8aba0 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableFuseableTest.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableFuseableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.flowable; import java.util.Arrays; @@ -17,7 +18,7 @@ import org.junit.Test; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.testsupport.TestHelper; public class FlowableFuseableTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableGroupByTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableGroupByTests.java index b7e4edcab4c..e37934eadd3 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableGroupByTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableGroupByTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableMergeTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableMergeTests.java index e200cd0f12b..d549c3fbb40 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableMergeTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableMergeTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableNotificationTest.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableNotificationTest.java index 2e2b95bbd87..08d1994fcb6 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableNotificationTest.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableNotificationTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableNullTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableNullTests.java index fd9712b64dd..748a12d3c33 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableNullTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableNullTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -42,21 +42,11 @@ public class FlowableNullTests extends RxJavaTest { // Static methods //*********************************************************** - @Test(expected = NullPointerException.class) - public void ambVarargsNull() { - Flowable.ambArray((Publisher[])null); - } - @Test(expected = NullPointerException.class) public void ambVarargsOneIsNull() { Flowable.ambArray(Flowable.never(), null).blockingLast(); } - @Test(expected = NullPointerException.class) - public void ambIterableNull() { - Flowable.amb((Iterable>)null); - } - @Test public void ambIterableIteratorNull() { Flowable.amb(new Iterable>() { @@ -74,16 +64,6 @@ public void ambIterableOneIsNull() { .assertError(NullPointerException.class); } - @Test(expected = NullPointerException.class) - public void combineLatestIterableNull() { - Flowable.combineLatestDelayError((Iterable>)null, new Function() { - @Override - public Object apply(Object[] v) { - return 1; - } - }); - } - @Test(expected = NullPointerException.class) public void combineLatestIterableIteratorNull() { Flowable.combineLatestDelayError(new Iterable>() { @@ -109,11 +89,6 @@ public Object apply(Object[] v) { }).blockingLast(); } - @Test(expected = NullPointerException.class) - public void combineLatestIterableFunctionNull() { - Flowable.combineLatestDelayError(Arrays.asList(just1), null); - } - @Test(expected = NullPointerException.class) public void combineLatestIterableFunctionReturnsNull() { Flowable.combineLatestDelayError(Arrays.asList(just1), new Function() { @@ -124,11 +99,6 @@ public Object apply(Object[] v) { }).blockingLast(); } - @Test(expected = NullPointerException.class) - public void concatIterableNull() { - Flowable.concat((Iterable>)null); - } - @Test(expected = NullPointerException.class) public void concatIterableIteratorNull() { Flowable.concat(new Iterable>() { @@ -144,32 +114,11 @@ public void concatIterableOneIsNull() { Flowable.concat(Arrays.asList(just1, null)).blockingLast(); } - @Test(expected = NullPointerException.class) - public void concatPublisherNull() { - Flowable.concat((Publisher>)null); - - } - - @Test(expected = NullPointerException.class) - public void concatArrayNull() { - Flowable.concatArray((Publisher[])null); - } - @Test(expected = NullPointerException.class) public void concatArrayOneIsNull() { Flowable.concatArray(just1, null).blockingLast(); } - @Test(expected = NullPointerException.class) - public void createNull() { - Flowable.unsafeCreate(null); - } - - @Test(expected = NullPointerException.class) - public void deferFunctionNull() { - Flowable.defer(null); - } - @Test(expected = NullPointerException.class) public void deferFunctionReturnsNull() { Flowable.defer(new Supplier>() { @@ -180,11 +129,6 @@ public Publisher get() { }).blockingLast(); } - @Test(expected = NullPointerException.class) - public void errorFunctionNull() { - Flowable.error((Supplier)null); - } - @Test(expected = NullPointerException.class) public void errorFunctionReturnsNull() { Flowable.error(new Supplier() { @@ -195,26 +139,11 @@ public Throwable get() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void errorThrowableNull() { - Flowable.error((Throwable)null); - } - - @Test(expected = NullPointerException.class) - public void fromArrayNull() { - Flowable.fromArray((Object[])null); - } - @Test(expected = NullPointerException.class) public void fromArrayOneIsNull() { Flowable.fromArray(1, null).blockingLast(); } - @Test(expected = NullPointerException.class) - public void fromCallableNull() { - Flowable.fromCallable(null); - } - @Test(expected = NullPointerException.class) public void fromCallableReturnsNull() { Flowable.fromCallable(new Callable() { @@ -225,11 +154,6 @@ public Object call() throws Exception { }).blockingLast(); } - @Test(expected = NullPointerException.class) - public void fromFutureNull() { - Flowable.fromFuture(null); - } - @Test public void fromFutureReturnsNull() { FutureTask f = new FutureTask<>(Functions.EMPTY_RUNNABLE, null); @@ -242,21 +166,6 @@ public void fromFutureReturnsNull() { ts.assertError(NullPointerException.class); } - @Test(expected = NullPointerException.class) - public void fromFutureTimedFutureNull() { - Flowable.fromFuture(null, 1, TimeUnit.SECONDS); - } - - @Test(expected = NullPointerException.class) - public void fromFutureTimedUnitNull() { - Flowable.fromFuture(new FutureTask<>(Functions.EMPTY_RUNNABLE, null), 1, null); - } - - @Test(expected = NullPointerException.class) - public void fromFutureTimedSchedulerNull() { - Flowable.fromFuture(new FutureTask<>(Functions.EMPTY_RUNNABLE, null), 1, TimeUnit.SECONDS, null); - } - @Test(expected = NullPointerException.class) public void fromFutureTimedReturnsNull() { FutureTask f = new FutureTask<>(Functions.EMPTY_RUNNABLE, null); @@ -264,16 +173,6 @@ public void fromFutureTimedReturnsNull() { Flowable.fromFuture(f, 1, TimeUnit.SECONDS).blockingLast(); } - @Test(expected = NullPointerException.class) - public void fromFutureSchedulerNull() { - Flowable.fromFuture(new FutureTask<>(Functions.EMPTY_RUNNABLE, null), null); - } - - @Test(expected = NullPointerException.class) - public void fromIterableNull() { - Flowable.fromIterable(null); - } - @Test(expected = NullPointerException.class) public void fromIterableIteratorNull() { Flowable.fromIterable(new Iterable() { @@ -289,16 +188,6 @@ public void fromIterableValueNull() { Flowable.fromIterable(Arrays.asList(1, null)).blockingLast(); } - @Test(expected = NullPointerException.class) - public void fromPublisherNull() { - Flowable.fromPublisher(null); - } - - @Test(expected = NullPointerException.class) - public void generateConsumerNull() { - Flowable.generate(null); - } - @Test(expected = NullPointerException.class) public void generateConsumerEmitsNull() { Flowable.generate(new Consumer>() { @@ -371,66 +260,6 @@ public Object apply(Object s, Emitter o) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void generateConsumerDisposeNull() { - BiConsumer> generator = new BiConsumer>() { - @Override - public void accept(Integer s, Emitter o) { - o.onNext(1); - } - }; - Flowable.generate(new Supplier() { - @Override - public Integer get() { - return 1; - } - }, generator, null); - } - - @Test(expected = NullPointerException.class) - public void generateFunctionDisposeNull() { - Flowable.generate(new Supplier() { - @Override - public Object get() { - return 1; - } - }, new BiFunction, Object>() { - @Override - public Object apply(Object s, Emitter o) { - o.onNext(1); return s; - } - }, null); - } - - @Test(expected = NullPointerException.class) - public void intervalUnitNull() { - Flowable.interval(1, null); - } - - public void intervalSchedulerNull() { - Flowable.interval(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void intervalPeriodUnitNull() { - Flowable.interval(1, 1, null); - } - - @Test(expected = NullPointerException.class) - public void intervalPeriodSchedulerNull() { - Flowable.interval(1, 1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void intervalRangeUnitNull() { - Flowable.intervalRange(1, 1, 1, 1, null); - } - - @Test(expected = NullPointerException.class) - public void intervalRangeSchedulerNull() { - Flowable.intervalRange(1, 1, 1, 1, TimeUnit.SECONDS, null); - } - @Test public void justNull() throws Exception { @SuppressWarnings("rawtypes") @@ -458,11 +287,6 @@ public void justNull() throws Exception { } } - @Test(expected = NullPointerException.class) - public void mergeIterableNull() { - Flowable.merge((Iterable>)null, 128, 128); - } - @Test(expected = NullPointerException.class) public void mergeIterableIteratorNull() { Flowable.merge(new Iterable>() { @@ -478,21 +302,11 @@ public void mergeIterableOneIsNull() { Flowable.merge(Arrays.asList(just1, null), 128, 128).blockingLast(); } - @Test(expected = NullPointerException.class) - public void mergeArrayNull() { - Flowable.mergeArray(128, 128, (Publisher[])null); - } - @Test(expected = NullPointerException.class) public void mergeArrayOneIsNull() { Flowable.mergeArray(128, 128, just1, null).blockingLast(); } - @Test(expected = NullPointerException.class) - public void mergeDelayErrorIterableNull() { - Flowable.mergeDelayError((Iterable>)null, 128, 128); - } - @Test(expected = NullPointerException.class) public void mergeDelayErrorIterableIteratorNull() { Flowable.mergeDelayError(new Iterable>() { @@ -508,66 +322,11 @@ public void mergeDelayErrorIterableOneIsNull() { Flowable.mergeDelayError(Arrays.asList(just1, null), 128, 128).blockingLast(); } - @Test(expected = NullPointerException.class) - public void mergeDelayErrorArrayNull() { - Flowable.mergeArrayDelayError(128, 128, (Publisher[])null); - } - @Test(expected = NullPointerException.class) public void mergeDelayErrorArrayOneIsNull() { Flowable.mergeArrayDelayError(128, 128, just1, null).blockingLast(); } - @Test(expected = NullPointerException.class) - public void sequenceEqualFirstNull() { - Flowable.sequenceEqual(null, just1); - } - - @Test(expected = NullPointerException.class) - public void sequenceEqualSecondNull() { - Flowable.sequenceEqual(just1, null); - } - - @Test(expected = NullPointerException.class) - public void sequenceEqualComparatorNull() { - Flowable.sequenceEqual(just1, just1, null); - } - - @Test(expected = NullPointerException.class) - public void switchOnNextNull() { - Flowable.switchOnNext(null); - } - - @Test(expected = NullPointerException.class) - public void timerUnitNull() { - Flowable.timer(1, null); - } - - @Test(expected = NullPointerException.class) - public void timerSchedulerNull() { - Flowable.timer(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void usingResourceSupplierNull() { - Flowable.using(null, new Function>() { - @Override - public Publisher apply(Object d) { - return just1; - } - }, Functions.emptyConsumer()); - } - - @Test(expected = NullPointerException.class) - public void usingFlowableSupplierNull() { - Flowable.using(new Supplier() { - @Override - public Object get() { - return 1; - } - }, null, Functions.emptyConsumer()); - } - @Test(expected = NullPointerException.class) public void usingFlowableSupplierReturnsNull() { Flowable.using(new Supplier() { @@ -583,31 +342,6 @@ public Publisher apply(Object d) { }, Functions.emptyConsumer()).blockingLast(); } - @Test(expected = NullPointerException.class) - public void usingDisposeNull() { - Flowable.using(new Supplier() { - @Override - public Object get() { - return 1; - } - }, new Function>() { - @Override - public Publisher apply(Object d) { - return just1; - } - }, null); - } - - @Test(expected = NullPointerException.class) - public void zipIterableNull() { - Flowable.zip((Iterable>)null, new Function() { - @Override - public Object apply(Object[] v) { - return 1; - } - }); - } - @Test(expected = NullPointerException.class) public void zipIterableIteratorNull() { Flowable.zip(new Iterable>() { @@ -623,11 +357,6 @@ public Object apply(Object[] v) { }).blockingLast(); } - @Test(expected = NullPointerException.class) - public void zipIterableFunctionNull() { - Flowable.zip(Arrays.asList(just1, just1), null); - } - @Test(expected = NullPointerException.class) public void zipIterableFunctionReturnsNull() { Flowable.zip(Arrays.asList(just1, just1), new Function() { @@ -663,11 +392,6 @@ public Object apply(Object[] a) { }, true, 128).blockingLast(); } - @Test(expected = NullPointerException.class) - public void zipIterable2FunctionNull() { - Flowable.zip(Arrays.asList(just1, just1), null, true, 128); - } - @Test(expected = NullPointerException.class) public void zipIterable2FunctionReturnsNull() { Flowable.zip(Arrays.asList(just1, just1), new Function() { @@ -682,26 +406,6 @@ public Object apply(Object[] a) { // Instance methods //************************************************************* - @Test(expected = NullPointerException.class) - public void allPredicateNull() { - just1.all(null); - } - - @Test(expected = NullPointerException.class) - public void ambWithNull() { - just1.ambWith(null); - } - - @Test(expected = NullPointerException.class) - public void anyPredicateNull() { - just1.any(null); - } - - @Test(expected = NullPointerException.class) - public void bufferSupplierNull() { - just1.buffer(1, 1, (Supplier>)null); - } - @Test(expected = NullPointerException.class) public void bufferSupplierReturnsNull() { just1.buffer(1, 1, new Supplier>() { @@ -712,21 +416,6 @@ public Collection get() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void bufferTimedUnitNull() { - just1.buffer(1L, 1L, null); - } - - @Test(expected = NullPointerException.class) - public void bufferTimedSchedulerNull() { - just1.buffer(1L, 1L, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void bufferTimedSupplierNull() { - just1.buffer(1L, 1L, TimeUnit.SECONDS, Schedulers.single(), null); - } - @Test(expected = NullPointerException.class) public void bufferTimedSupplierReturnsNull() { just1.buffer(1L, 1L, TimeUnit.SECONDS, Schedulers.single(), new Supplier>() { @@ -737,21 +426,6 @@ public Collection get() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void bufferOpenCloseOpenNull() { - just1.buffer(null, new Function>() { - @Override - public Publisher apply(Object o) { - return just1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void bufferOpenCloseCloseNull() { - just1.buffer(just1, (Function>)null); - } - @Test(expected = NullPointerException.class) public void bufferOpenCloseCloseReturnsNull() { just1.buffer(just1, new Function>() { @@ -762,16 +436,6 @@ public Publisher apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void bufferBoundaryNull() { - just1.buffer((Publisher)null); - } - - @Test(expected = NullPointerException.class) - public void bufferBoundarySupplierNull() { - just1.buffer(just1, (Supplier>)null); - } - @Test(expected = NullPointerException.class) public void bufferBoundarySupplierReturnsNull() { just1.buffer(just1, new Supplier>() { @@ -782,19 +446,6 @@ public Collection get() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void castNull() { - just1.cast(null); - } - - @Test(expected = NullPointerException.class) - public void collectInitialSupplierNull() { - just1.collect((Supplier)null, new BiConsumer() { - @Override - public void accept(Integer a, Integer b) { } - }); - } - @Test(expected = NullPointerException.class) public void collectInitialSupplierReturnsNull() { just1.collect(new Supplier() { @@ -808,39 +459,6 @@ public void accept(Object a, Integer b) { } }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void collectInitialCollectorNull() { - just1.collect(new Supplier() { - @Override - public Object get() { - return 1; - } - }, null); - } - - @Test(expected = NullPointerException.class) - public void collectIntoInitialNull() { - just1.collectInto(null, new BiConsumer() { - @Override - public void accept(Object a, Integer b) { } - }); - } - - @Test(expected = NullPointerException.class) - public void collectIntoCollectorNull() { - just1.collectInto(1, null); - } - - @Test(expected = NullPointerException.class) - public void composeNull() { - just1.compose(null); - } - - @Test(expected = NullPointerException.class) - public void concatMapNull() { - just1.concatMap(null); - } - @Test(expected = NullPointerException.class) public void concatMapReturnsNull() { just1.concatMap(new Function>() { @@ -851,11 +469,6 @@ public Publisher apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void concatMapIterableNull() { - just1.concatMapIterable(null); - } - @Test(expected = NullPointerException.class) public void concatMapIterableReturnNull() { just1.concatMapIterable(new Function>() { @@ -881,21 +494,6 @@ public Iterator iterator() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void concatWithNull() { - just1.concatWith((Publisher)null); - } - - @Test(expected = NullPointerException.class) - public void containsNull() { - just1.contains(null); - } - - @Test(expected = NullPointerException.class) - public void debounceFunctionNull() { - just1.debounce(null); - } - @Test(expected = NullPointerException.class) public void debounceFunctionReturnsNull() { just1.debounce(new Function>() { @@ -906,26 +504,6 @@ public Publisher apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void debounceTimedUnitNull() { - just1.debounce(1, null); - } - - @Test(expected = NullPointerException.class) - public void debounceTimedSchedulerNull() { - just1.debounce(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void defaultIfEmptyNull() { - just1.defaultIfEmpty(null); - } - - @Test(expected = NullPointerException.class) - public void delayWithFunctionNull() { - just1.delay(null); - } - @Test(expected = NullPointerException.class) public void delayWithFunctionReturnsNull() { just1.delay(new Function>() { @@ -936,61 +514,6 @@ public Publisher apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void delayTimedUnitNull() { - just1.delay(1, null); - } - - @Test(expected = NullPointerException.class) - public void delayTimedSchedulerNull() { - just1.delay(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void delaySubscriptionTimedUnitNull() { - just1.delaySubscription(1, null); - } - - @Test(expected = NullPointerException.class) - public void delaySubscriptionTimedSchedulerNull() { - just1.delaySubscription(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void delaySubscriptionSupplierNull() { - just1.delaySubscription((Publisher)null); - } - - @Test(expected = NullPointerException.class) - public void delaySubscriptionFunctionNull() { - just1.delaySubscription((Publisher)null); - } - - @Test(expected = NullPointerException.class) - public void delayBothInitialSupplierNull() { - just1.delay(null, new Function>() { - @Override - public Publisher apply(Integer v) { - return just1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void delayBothInitialSupplierReturnsNull() { - just1.delay(null, new Function>() { - @Override - public Publisher apply(Integer v) { - return just1; - } - }).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void delayBothItemSupplierNull() { - just1.delay(just1, null); - } - @Test(expected = NullPointerException.class) public void delayBothItemSupplierReturnsNull() { just1.delay(just1, new Function>() { @@ -1001,21 +524,6 @@ public Publisher apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void distinctFunctionNull() { - just1.distinct(null); - } - - @Test(expected = NullPointerException.class) - public void distinctSupplierNull() { - just1.distinct(new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, null); - } - @Test(expected = NullPointerException.class) public void distinctSupplierReturnsNull() { just1.distinct(new Function() { @@ -1041,16 +549,6 @@ public Object apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void distinctUntilChangedFunctionNull() { - just1.distinctUntilChanged((Function)null); - } - - @Test(expected = NullPointerException.class) - public void distinctUntilChangedBiPredicateNull() { - just1.distinctUntilChanged((BiPredicate)null); - } - @Test public void distinctUntilChangedFunctionReturnsNull() { Flowable.range(1, 2).distinctUntilChanged(new Function() { @@ -1061,109 +559,6 @@ public Object apply(Integer v) { }).test().assertResult(1); } - @Test(expected = NullPointerException.class) - public void doOnCancelNull() { - just1.doOnCancel(null); - } - - @Test(expected = NullPointerException.class) - public void doOnCompleteNull() { - just1.doOnComplete(null); - } - - @Test(expected = NullPointerException.class) - public void doOnEachSupplierNull() { - just1.doOnEach((Consumer>)null); - } - - @Test(expected = NullPointerException.class) - public void doOnEachSubscriberNull() { - just1.doOnEach((Subscriber)null); - } - - @Test(expected = NullPointerException.class) - public void doOnErrorNull() { - just1.doOnError(null); - } - - @Test(expected = NullPointerException.class) - public void doOnLifecycleOnSubscribeNull() { - just1.doOnLifecycle(null, new LongConsumer() { - @Override - public void accept(long v) { } - }, new Action() { - @Override - public void run() { } - }); - } - - @Test(expected = NullPointerException.class) - public void doOnLifecycleOnRequestNull() { - just1.doOnLifecycle(new Consumer() { - @Override - public void accept(Subscription s) { } - }, null, new Action() { - @Override - public void run() { } - }); - } - - @Test(expected = NullPointerException.class) - public void doOnLifecycleOnCancelNull() { - just1.doOnLifecycle(new Consumer() { - @Override - public void accept(Subscription s) { } - }, new LongConsumer() { - @Override - public void accept(long v) { } - }, null); - } - - @Test(expected = NullPointerException.class) - public void doOnNextNull() { - just1.doOnNext(null); - } - - @Test(expected = NullPointerException.class) - public void doOnRequestNull() { - just1.doOnRequest(null); - } - - @Test(expected = NullPointerException.class) - public void doOnSubscribeNull() { - just1.doOnSubscribe(null); - } - - @Test(expected = NullPointerException.class) - public void doOnTerminatedNull() { - just1.doOnTerminate(null); - } - - @Test(expected = NullPointerException.class) - public void elementAtNull() { - just1.elementAt(1, null); - } - - @Test(expected = NullPointerException.class) - public void filterNull() { - just1.filter(null); - } - - @Test(expected = NullPointerException.class) - public void doAfterTerminateNull() { - just1.doAfterTerminate(null); - } - - @Test(expected = NullPointerException.class) - public void firstNull() { - just1.first(null); - } - - @Test(expected = NullPointerException.class) - public void flatMapNull() { - just1.flatMap(null); - } - @Test(expected = NullPointerException.class) public void flatMapFunctionReturnsNull() { just1.flatMap(new Function>() { @@ -1174,21 +569,6 @@ public Publisher apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void flatMapNotificationOnNextNull() { - just1.flatMap(null, new Function>() { - @Override - public Publisher apply(Throwable e) { - return just1; - } - }, new Supplier>() { - @Override - public Publisher get() { - return just1; - } - }); - } - @Test(expected = NullPointerException.class) public void flatMapNotificationOnNextReturnsNull() { just1.flatMap(new Function>() { @@ -1209,36 +589,6 @@ public Publisher get() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void flatMapNotificationOnErrorNull() { - just1.flatMap(new Function>() { - @Override - public Publisher apply(Integer v) { - return just1; - } - }, null, new Supplier>() { - @Override - public Publisher get() { - return just1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void flatMapNotificationOnCompleteNull() { - just1.flatMap(new Function>() { - @Override - public Publisher apply(Integer v) { - return just1; - } - }, new Function>() { - @Override - public Publisher apply(Throwable e) { - return just1; - } - }, null); - } - @Test(expected = NullPointerException.class) public void flatMapNotificationOnCompleteReturnsNull() { just1.flatMap(new Function>() { @@ -1259,16 +609,6 @@ public Publisher get() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void flatMapCombinerMapperNull() { - just1.flatMap(null, new BiFunction() { - @Override - public Object apply(Integer a, Object b) { - return 1; - } - }); - } - @Test(expected = NullPointerException.class) public void flatMapCombinerMapperReturnsNull() { just1.flatMap(new Function>() { @@ -1284,16 +624,6 @@ public Object apply(Integer a, Object b) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void flatMapCombinerCombinerNull() { - just1.flatMap(new Function>() { - @Override - public Publisher apply(Integer v) { - return just1; - } - }, null); - } - @Test(expected = NullPointerException.class) public void flatMapCombinerCombinerReturnsNull() { just1.flatMap(new Function>() { @@ -1309,11 +639,6 @@ public Object apply(Integer a, Integer b) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void flatMapIterableMapperNull() { - just1.flatMapIterable(null); - } - @Test(expected = NullPointerException.class) public void flatMapIterableMapperReturnsNull() { just1.flatMapIterable(new Function>() { @@ -1349,16 +674,6 @@ public Iterable apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void flatMapIterableCombinerNull() { - just1.flatMapIterable(new Function>() { - @Override - public Iterable apply(Integer v) { - return Arrays.asList(1); - } - }, null); - } - @Test(expected = NullPointerException.class) public void flatMapIterableCombinerReturnsNull() { just1.flatMapIterable(new Function>() { @@ -1374,44 +689,6 @@ public Object apply(Integer a, Integer b) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void forEachNull() { - just1.forEach(null); - } - - @Test(expected = NullPointerException.class) - public void forEachWhileNull() { - just1.forEachWhile(null); - } - - @Test(expected = NullPointerException.class) - public void forEachWhileOnErrorNull() { - just1.forEachWhile(new Predicate() { - @Override - public boolean test(Integer v) { - return true; - } - }, null); - } - - @Test(expected = NullPointerException.class) - public void forEachWhileOnCompleteNull() { - just1.forEachWhile(new Predicate() { - @Override - public boolean test(Integer v) { - return true; - } - }, new Consumer() { - @Override - public void accept(Throwable e) { } - }, null); - } - - @Test(expected = NullPointerException.class) - public void groupByNull() { - just1.groupBy(null); - } - public void groupByKeyNull() { just1.groupBy(new Function() { @Override @@ -1421,16 +698,6 @@ public Object apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void groupByValueNull() { - just1.groupBy(new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, null); - } - @Test(expected = NullPointerException.class) public void groupByValueReturnsNull() { just1.groupBy(new Function() { @@ -1446,16 +713,6 @@ public Object apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void lastNull() { - just1.last(null); - } - - @Test(expected = NullPointerException.class) - public void liftNull() { - just1.lift(null); - } - @Test(expected = NullPointerException.class) public void liftReturnsNull() { just1.lift(new FlowableOperator() { @@ -1466,11 +723,6 @@ public Subscriber apply(Subscriber s) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void mapNull() { - just1.map(null); - } - @Test(expected = NullPointerException.class) public void mapReturnsNull() { just1.map(new Function() { @@ -1481,36 +733,6 @@ public Object apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void mergeWithNull() { - just1.mergeWith((Publisher)null); - } - - @Test(expected = NullPointerException.class) - public void observeOnNull() { - just1.observeOn(null); - } - - @Test(expected = NullPointerException.class) - public void ofTypeNull() { - just1.ofType(null); - } - - @Test(expected = NullPointerException.class) - public void onBackpressureBufferOverflowNull() { - just1.onBackpressureBuffer(10, null); - } - - @Test(expected = NullPointerException.class) - public void onBackpressureDropActionNull() { - just1.onBackpressureDrop(null); - } - - @Test(expected = NullPointerException.class) - public void onErrorResumeNextNull() { - just1.onErrorResumeNext(null); - } - @Test public void onErrorResumeNextFunctionReturnsNull() { try { @@ -1529,21 +751,6 @@ public Publisher apply(Throwable e) { } } - @Test(expected = NullPointerException.class) - public void onErrorResumeWithNull() { - just1.onErrorResumeWith(null); - } - - @Test(expected = NullPointerException.class) - public void onErrorReturnFunctionNull() { - just1.onErrorReturn(null); - } - - @Test(expected = NullPointerException.class) - public void onErrorReturnValueNull() { - just1.onErrorReturnItem(null); - } - @Test public void onErrorReturnFunctionReturnsNull() { try { @@ -1562,11 +769,6 @@ public Object apply(Throwable e) { } } - @Test(expected = NullPointerException.class) - public void publishFunctionNull() { - just1.publish(null); - } - @Test(expected = NullPointerException.class) public void publishFunctionReturnsNull() { just1.publish(new Function, Publisher>() { @@ -1577,11 +779,6 @@ public Publisher apply(Flowable v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void reduceFunctionNull() { - just1.reduce(null); - } - @Test(expected = NullPointerException.class) public void reduceFunctionReturnsNull() { Flowable.just(1, 1).reduce(new BiFunction() { @@ -1592,21 +789,6 @@ public Integer apply(Integer a, Integer b) { }).toFlowable().blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void reduceSeedNull() { - just1.reduce(null, new BiFunction() { - @Override - public Object apply(Object a, Integer b) { - return 1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void reduceSeedFunctionNull() { - just1.reduce(1, null); - } - @Test(expected = NullPointerException.class) public void reduceSeedFunctionReturnsNull() { just1.reduce(1, new BiFunction() { @@ -1642,16 +824,6 @@ public Object apply(Object a, Integer b) { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void repeatUntilNull() { - just1.repeatUntil(null); - } - - @Test(expected = NullPointerException.class) - public void repeatWhenNull() { - just1.repeatWhen(null); - } - @Test(expected = NullPointerException.class) public void repeatWhenFunctionReturnsNull() { just1.repeatWhen(new Function, Publisher>() { @@ -1677,454 +849,124 @@ public Publisher apply(Flowable f) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void replayBoundedSelectorNull() { - just1.replay((Function, Flowable>)null, 1, 1, TimeUnit.SECONDS); - } - @Test(expected = NullPointerException.class) public void replayBoundedSelectorReturnsNull() { just1.replay(new Function, Publisher>() { - @Override - public Publisher apply(Flowable v) { - return null; - } - }, 1, 1, TimeUnit.SECONDS).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void replayBoundedUnitNull() { - just1.replay(new Function, Publisher>() { - @Override - public Publisher apply(Flowable v) { - return v; - } - }, 1, 1, null).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void replayBoundedSchedulerNull() { - just1.replay(new Function, Publisher>() { - @Override - public Publisher apply(Flowable v) { - return v; - } - }, 1, 1, TimeUnit.SECONDS, null).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void replayTimeBoundedSelectorNull() { - just1.replay(null, 1, TimeUnit.SECONDS, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void replayTimeBoundedSelectorReturnsNull() { - just1.replay(new Function, Publisher>() { - @Override - public Publisher apply(Flowable v) { - return null; - } - }, 1, TimeUnit.SECONDS, Schedulers.single()).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void replaySelectorTimeBoundedUnitNull() { - just1.replay(new Function, Publisher>() { - @Override - public Publisher apply(Flowable v) { - return v; - } - }, 1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void replaySelectorTimeBoundedSchedulerNull() { - just1.replay(new Function, Publisher>() { - @Override - public Publisher apply(Flowable v) { - return v; - } - }, 1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void replayTimeSizeBoundedUnitNull() { - just1.replay(1, 1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void replayTimeSizeBoundedSchedulerNull() { - just1.replay(1, 1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void replayTimeBoundedUnitNull() { - just1.replay(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void replayTimeBoundedSchedulerNull() { - just1.replay(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void retryFunctionNull() { - just1.retry((BiPredicate)null); - } - - @Test(expected = NullPointerException.class) - public void retryCountFunctionNull() { - just1.retry(1, null); - } - - @Test(expected = NullPointerException.class) - public void retryPredicateNull() { - just1.retry((Predicate)null); - } - - @Test(expected = NullPointerException.class) - public void retryWhenFunctionNull() { - just1.retryWhen(null); - } - - @Test(expected = NullPointerException.class) - public void retryWhenFunctionReturnsNull() { - Flowable.error(new TestException()).retryWhen(new Function, Publisher>() { - @Override - public Publisher apply(Flowable f) { - return null; - } - }).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void retryUntil() { - just1.retryUntil(null); - } - - @Test(expected = NullPointerException.class) - public void safeSubscribeNull() { - just1.safeSubscribe(null); - } - - @Test(expected = NullPointerException.class) - public void sampleUnitNull() { - just1.sample(1, null); - } - - @Test(expected = NullPointerException.class) - public void sampleSchedulerNull() { - just1.sample(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void samplePublisherNull() { - just1.sample(null); - } - - @Test(expected = NullPointerException.class) - public void scanFunctionNull() { - just1.scan(null); - } - - @Test(expected = NullPointerException.class) - public void scanFunctionReturnsNull() { - Flowable.just(1, 1).scan(new BiFunction() { - @Override - public Integer apply(Integer a, Integer b) { - return null; - } - }).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void scanSeedNull() { - just1.scan(null, new BiFunction() { - @Override - public Object apply(Object a, Integer b) { - return 1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void scanSeedFunctionNull() { - just1.scan(1, null); - } - - @Test(expected = NullPointerException.class) - public void scanSeedFunctionReturnsNull() { - just1.scan(1, new BiFunction() { - @Override - public Integer apply(Integer a, Integer b) { - return null; - } - }).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void scanSeedSupplierNull() { - just1.scanWith(null, new BiFunction() { - @Override - public Object apply(Object a, Integer b) { - return 1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void scanSeedSupplierReturnsNull() { - just1.scanWith(new Supplier() { - @Override - public Object get() { - return null; - } - }, new BiFunction() { - @Override - public Object apply(Object a, Integer b) { - return 1; - } - }).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void scanSeedSupplierFunctionNull() { - just1.scanWith(new Supplier() { - @Override - public Object get() { - return 1; - } - }, null); - } - - @Test(expected = NullPointerException.class) - public void scanSeedSupplierFunctionReturnsNull() { - just1.scanWith(new Supplier() { - @Override - public Object get() { - return 1; - } - }, new BiFunction() { - @Override - public Object apply(Object a, Integer b) { - return null; - } - }).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void singleNull() { - just1.single(null); - } - - @Test(expected = NullPointerException.class) - public void skipTimedUnitNull() { - just1.skip(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void skipTimedSchedulerNull() { - just1.skip(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void skipLastTimedUnitNull() { - just1.skipLast(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void skipLastTimedSchedulerNull() { - just1.skipLast(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void skipUntilNull() { - just1.skipUntil(null); - } - - @Test(expected = NullPointerException.class) - public void skipWhileNull() { - just1.skipWhile(null); - } - - @Test(expected = NullPointerException.class) - public void startWithIterableNull() { - just1.startWithIterable((Iterable)null); - } - - @Test(expected = NullPointerException.class) - public void startWithIterableIteratorNull() { - just1.startWithIterable(new Iterable() { - @Override - public Iterator iterator() { - return null; - } - }).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void startWithIterableOneNull() { - just1.startWithIterable(Arrays.asList(1, null)).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void startWithSingleNull() { - just1.startWithItem((Integer)null); - } - - @Test(expected = NullPointerException.class) - public void startWithPublisherNull() { - just1.startWith((Publisher)null); - } - - @Test(expected = NullPointerException.class) - public void startWithArrayNull() { - just1.startWithArray((Integer[])null); - } - - @Test(expected = NullPointerException.class) - public void startWithArrayOneNull() { - just1.startWithArray(1, null).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void subscribeOnNextNull() { - just1.subscribe((Consumer)null); - } - - @Test(expected = NullPointerException.class) - public void subscribeOnErrorNull() { - just1.subscribe(Functions.emptyConsumer(), null); - } - - @Test(expected = NullPointerException.class) - public void subscribeOnCompleteNull() { - just1.subscribe(Functions.emptyConsumer(), Functions.emptyConsumer(), null); - } - - @Test(expected = NullPointerException.class) - public void subscribeNull() { - just1.subscribe((Subscriber)null); - } - - @Test(expected = NullPointerException.class) - public void subscribeNull2() { - just1.subscribe((FlowableSubscriber)null); - } - - @Test(expected = NullPointerException.class) - public void subscribeOnNull() { - just1.subscribeOn(null); - } - - @Test(expected = NullPointerException.class) - public void switchIfEmptyNull() { - just1.switchIfEmpty(null); - } - - @Test(expected = NullPointerException.class) - public void switchMapNull() { - just1.switchMap(null); - } - - @Test(expected = NullPointerException.class) - public void switchMapFunctionReturnsNull() { - just1.switchMap(new Function>() { - @Override - public Publisher apply(Integer v) { - return null; - } - }).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void takeTimedUnitNull() { - just1.take(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void takeTimedSchedulerNull() { - just1.take(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void takeLastTimedUnitNull() { - just1.takeLast(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void takeLastSizeTimedUnitNull() { - just1.takeLast(1, 1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void takeLastTimedSchedulerNull() { - just1.takeLast(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void takeLastSizeTimedSchedulerNull() { - just1.takeLast(1, 1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void takeUntilPredicateNull() { - just1.takeUntil((Predicate)null); + @Override + public Publisher apply(Flowable v) { + return null; + } + }, 1, 1, TimeUnit.SECONDS).blockingSubscribe(); } @Test(expected = NullPointerException.class) - public void takeUntilPublisherNull() { - just1.takeUntil((Publisher)null); + public void replayTimeBoundedSelectorReturnsNull() { + just1.replay(new Function, Publisher>() { + @Override + public Publisher apply(Flowable v) { + return null; + } + }, 1, TimeUnit.SECONDS, Schedulers.single()).blockingSubscribe(); } @Test(expected = NullPointerException.class) - public void takeWhileNull() { - just1.takeWhile(null); + public void retryWhenFunctionReturnsNull() { + Flowable.error(new TestException()).retryWhen(new Function, Publisher>() { + @Override + public Publisher apply(Flowable f) { + return null; + } + }).blockingSubscribe(); } @Test(expected = NullPointerException.class) - public void throttleFirstUnitNull() { - just1.throttleFirst(1, null, Schedulers.single()); + public void scanFunctionReturnsNull() { + Flowable.just(1, 1).scan(new BiFunction() { + @Override + public Integer apply(Integer a, Integer b) { + return null; + } + }).blockingSubscribe(); } @Test(expected = NullPointerException.class) - public void throttleFirstSchedulerNull() { - just1.throttleFirst(1, TimeUnit.SECONDS, null); + public void scanSeedNull() { + just1.scan(null, new BiFunction() { + @Override + public Object apply(Object a, Integer b) { + return 1; + } + }); } @Test(expected = NullPointerException.class) - public void throttleLastUnitNull() { - just1.throttleLast(1, null, Schedulers.single()); + public void scanSeedFunctionReturnsNull() { + just1.scan(1, new BiFunction() { + @Override + public Integer apply(Integer a, Integer b) { + return null; + } + }).blockingSubscribe(); } @Test(expected = NullPointerException.class) - public void throttleLastSchedulerNull() { - just1.throttleLast(1, TimeUnit.SECONDS, null); + public void scanSeedSupplierReturnsNull() { + just1.scanWith(new Supplier() { + @Override + public Object get() { + return null; + } + }, new BiFunction() { + @Override + public Object apply(Object a, Integer b) { + return 1; + } + }).blockingSubscribe(); } @Test(expected = NullPointerException.class) - public void throttleWithTimeoutUnitNull() { - just1.throttleWithTimeout(1, null, Schedulers.single()); + public void scanSeedSupplierFunctionReturnsNull() { + just1.scanWith(new Supplier() { + @Override + public Object get() { + return 1; + } + }, new BiFunction() { + @Override + public Object apply(Object a, Integer b) { + return null; + } + }).blockingSubscribe(); } @Test(expected = NullPointerException.class) - public void throttleWithTimeoutSchedulerNull() { - just1.throttleWithTimeout(1, TimeUnit.SECONDS, null); + public void startWithIterableIteratorNull() { + just1.startWithIterable(new Iterable() { + @Override + public Iterator iterator() { + return null; + } + }).blockingSubscribe(); } @Test(expected = NullPointerException.class) - public void timeIntervalUnitNull() { - just1.timeInterval(null, Schedulers.single()); + public void startWithIterableOneNull() { + just1.startWithIterable(Arrays.asList(1, null)).blockingSubscribe(); } @Test(expected = NullPointerException.class) - public void timeIntervalSchedulerNull() { - just1.timeInterval(TimeUnit.SECONDS, null); + public void startWithArrayOneNull() { + just1.startWithArray(1, null).blockingSubscribe(); } @Test(expected = NullPointerException.class) - public void timeoutSelectorNull() { - just1.timeout(null); + public void switchMapFunctionReturnsNull() { + just1.switchMap(new Function>() { + @Override + public Publisher apply(Integer v) { + return null; + } + }).blockingSubscribe(); } @Test(expected = NullPointerException.class) @@ -2147,36 +989,6 @@ public Publisher apply(Integer v) { }, null); } - @Test(expected = NullPointerException.class) - public void timeoutUnitNull() { - just1.timeout(1, null, Schedulers.single(), just1); - } - - @Test(expected = NullPointerException.class) - public void timeouOtherNull() { - just1.timeout(1, TimeUnit.SECONDS, Schedulers.single(), null); - } - - @Test(expected = NullPointerException.class) - public void timeouSchedulerNull() { - just1.timeout(1, TimeUnit.SECONDS, null, just1); - } - - @Test(expected = NullPointerException.class) - public void timeoutFirstNull() { - just1.timeout((Publisher)null, new Function>() { - @Override - public Publisher apply(Integer v) { - return just1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void timeoutFirstItemNull() { - just1.timeout(just1, null); - } - @Test(expected = NullPointerException.class) public void timeoutFirstItemReturnsNull() { just1.timeout(Flowable.never(), new Function>() { @@ -2197,16 +1009,6 @@ public void timestampSchedulerNull() { just1.timestamp(TimeUnit.SECONDS, null); } - @Test(expected = NullPointerException.class) - public void toNull() { - just1.to(null); - } - - @Test(expected = NullPointerException.class) - public void toListNull() { - just1.toList(null); - } - @Test(expected = NullPointerException.class) public void toListSupplierReturnsNull() { just1.toList(new Supplier>() { @@ -2227,26 +1029,6 @@ public Collection get() { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void toSortedListNull() { - just1.toSortedList(null); - } - - @Test(expected = NullPointerException.class) - public void toMapKeyNullAllowed() { - just1.toMap(null); - } - - @Test(expected = NullPointerException.class) - public void toMapValueNull() { - just1.toMap(new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, null); - } - @Test public void toMapValueSelectorReturnsNull() { just1.toMap(new Function() { @@ -2262,21 +1044,6 @@ public Object apply(Integer v) { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void toMapMapSupplierNull() { - just1.toMap(new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, null); - } - @Test(expected = NullPointerException.class) public void toMapMapSupplierReturnsNull() { just1.toMap(new Function() { @@ -2297,21 +1064,6 @@ public Map get() { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void toMultimapKeyNull() { - just1.toMultimap(null); - } - - @Test(expected = NullPointerException.class) - public void toMultimapValueNull() { - just1.toMultimap(new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, null); - } - @Test public void toMultiMapValueSelectorReturnsNullAllowed() { just1.toMap(new Function() { @@ -2327,21 +1079,6 @@ public Object apply(Integer v) { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void toMultimapMapMapSupplierNull() { - just1.toMultimap(new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, null); - } - @Test(expected = NullPointerException.class) public void toMultimapMapSupplierReturnsNull() { just1.toMultimap(new Function() { @@ -2362,26 +1099,6 @@ public Map> get() { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void toMultimapMapMapCollectionSupplierNull() { - just1.toMultimap(new Function() { - @Override - public Integer apply(Integer v) { - return v; - } - }, new Function() { - @Override - public Integer apply(Integer v) { - return v; - } - }, new Supplier>>() { - @Override - public Map> get() { - return new HashMap<>(); - } - }, null); - } - @Test(expected = NullPointerException.class) public void toMultimapMapCollectionSupplierReturnsNull() { just1.toMultimap(new Function() { @@ -2407,36 +1124,6 @@ public Collection apply(Integer v) { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void unsubscribeOnNull() { - just1.unsubscribeOn(null); - } - - @Test(expected = NullPointerException.class) - public void windowTimedUnitNull() { - just1.window(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void windowSizeTimedUnitNull() { - just1.window(1, null, Schedulers.single(), 1); - } - - @Test(expected = NullPointerException.class) - public void windowTimedSchedulerNull() { - just1.window(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void windowSizeTimedSchedulerNull() { - just1.window(1, TimeUnit.SECONDS, null, 1); - } - - @Test(expected = NullPointerException.class) - public void windowBoundaryNull() { - just1.window((Publisher)null); - } - @Test(expected = NullPointerException.class) public void windowOpenCloseOpenNull() { just1.window(null, new Function>() { @@ -2447,11 +1134,6 @@ public Publisher apply(Object v) { }); } - @Test(expected = NullPointerException.class) - public void windowOpenCloseCloseNull() { - just1.window(just1, null); - } - @Test(expected = NullPointerException.class) public void windowOpenCloseCloseReturnsNull() { Flowable.never().window(just1, new Function>() { @@ -2472,11 +1154,6 @@ public Object apply(Integer a, Object b) { }); } - @Test(expected = NullPointerException.class) - public void withLatestFromCombinerNull() { - just1.withLatestFrom(just1, null); - } - @Test(expected = NullPointerException.class) public void withLatestFromCombinerReturnsNull() { just1.withLatestFrom(just1, new BiFunction() { @@ -2497,11 +1174,6 @@ public Object apply(Integer a, Integer b) { }); } - @Test(expected = NullPointerException.class) - public void zipWithIterableCombinerNull() { - just1.zipWith(Arrays.asList(1), null); - } - @Test(expected = NullPointerException.class) public void zipWithIterableCombinerReturnsNull() { just1.zipWith(Arrays.asList(1), new BiFunction() { @@ -2547,11 +1219,6 @@ public Object apply(Integer a, Integer b) { }); } - @Test(expected = NullPointerException.class) - public void zipWithCombinerNull() { - just1.zipWith(just1, null); - } - @Test(expected = NullPointerException.class) public void zipWithCombinerReturnsNull() { just1.zipWith(just1, new BiFunction() { @@ -2636,34 +1303,6 @@ public void serializedSubjectOnErrorNull() { processor.blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void doOnLifecycleOnDisposeNull() { - just1.doOnLifecycle(new Consumer() { - @Override - public void accept(Subscription s) { } - }, - new LongConsumer() { - @Override - public void accept(long v) throws Exception { } - }, - null); - } - - @Test(expected = NullPointerException.class) - public void zipWithFlowableNull() { - just1.zipWith((Flowable)null, new BiFunction() { - @Override - public Object apply(Integer a, Integer b) { - return 1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void unsafeSubscribeNull() { - just1.subscribe((FlowableSubscriber)null); - } - @Test(expected = NullPointerException.class) public void combineLatestDelayErrorIterableFunctionReturnsNull() { Flowable.combineLatestDelayError(Arrays.asList(just1), new Function() { @@ -2674,26 +1313,6 @@ public Object apply(Object[] v) { }, 128).blockingLast(); } - @Test(expected = NullPointerException.class) - public void combineLatestDelayErrorIterableFunctionNull() { - Flowable.combineLatestDelayError(Arrays.asList(just1), null, 128); - } - - @Test(expected = NullPointerException.class) - public void concatFlowableNull() { - Flowable.concat((Flowable>)null); - } - - @Test(expected = NullPointerException.class) - public void combineLatestDelayErrorIterableNull() { - Flowable.combineLatestDelayError((Iterable>)null, new Function() { - @Override - public Object apply(Object[] v) { - return 1; - } - }, 128); - } - @Test(expected = NullPointerException.class) public void combineLatestDelayErrorIterableIteratorNull() { Flowable.combineLatestDelayError(new Iterable>() { @@ -2709,11 +1328,6 @@ public Object apply(Object[] v) { }, 128).blockingLast(); } - @Test(expected = NullPointerException.class) - public void doOnDisposeNull() { - just1.doOnCancel(null); - } - @Test(expected = NullPointerException.class) public void combineLatestDelayErrorIterableOneIsNull() { Flowable.combineLatestDelayError(Arrays.asList(Flowable.never(), null), new Function() { @@ -2723,24 +1337,4 @@ public Object apply(Object[] v) { } }, 128).blockingLast(); } - - @Test(expected = NullPointerException.class) - public void takeUntilFlowableNull() { - just1.takeUntil((Flowable)null); - } - - @Test(expected = NullPointerException.class) - public void startWithFlowableNull() { - just1.startWith((Flowable)null); - } - - @Test(expected = NullPointerException.class) - public void delaySubscriptionOtherNull() { - just1.delaySubscription((Flowable)null); - } - - @Test(expected = NullPointerException.class) - public void sampleFlowableNull() { - just1.sample(null); - } } diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableReduceTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableReduceTests.java index 1e6abe83c9d..5dd3c28cb25 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableReduceTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableReduceTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableStartWithTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableStartWithTests.java index 7ac13a4bd6e..28549b1a90f 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableStartWithTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableStartWithTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableSubscriberTest.java index 2a27aaada08..b1eb9ce600f 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableTests.java index 3d462efe0b3..1fa80701be2 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -999,13 +999,6 @@ public void emptyIsEmpty() { verify(w, never()).onError(any(Throwable.class)); } - @Test(expected = NullPointerException.class) - public void forEachWithNull() { - Flowable.error(new Exception("boo")) - // - .forEach(null); - } - @Test public void extend() { final TestSubscriber subscriber = new TestSubscriber<>(); diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableThrottleLastTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableThrottleLastTests.java index c6db747cf1a..c5c858c4303 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableThrottleLastTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableThrottleLastTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,10 +13,14 @@ package io.reactivex.rxjava3.flowable; -import static org.mockito.Mockito.inOrder; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; import java.util.concurrent.TimeUnit; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.Action; import org.junit.Test; import org.mockito.InOrder; import org.reactivestreams.Subscriber; @@ -28,6 +32,72 @@ public class FlowableThrottleLastTests extends RxJavaTest { + @Test + public void throttleWithDroppedCallbackException() throws Throwable { + Subscriber subscriber = TestHelper.mockSubscriber(); + Action whenDisposed = mock(Action.class); + + TestScheduler s = new TestScheduler(); + PublishProcessor o = PublishProcessor.create(); + o.doOnCancel(whenDisposed) + .throttleLast(500, TimeUnit.MILLISECONDS, s, e-> { + if (e == 1) { + throw new TestException("forced"); + } + }) + .subscribe(subscriber); + + // send events with simulated time increments + s.advanceTimeTo(0, TimeUnit.MILLISECONDS); + o.onNext(1); // skip + o.onNext(2); // deliver + s.advanceTimeTo(501, TimeUnit.MILLISECONDS); + + InOrder inOrder = inOrder(subscriber); + inOrder.verify(subscriber).onError(any(TestException.class)); + inOrder.verifyNoMoreInteractions(); + verify(whenDisposed).run(); + } + + @Test + public void throttleWithDroppedCallback() { + Subscriber subscriber = TestHelper.mockSubscriber(); + Observer dropCallbackObserver = TestHelper.mockObserver(); + + TestScheduler s = new TestScheduler(); + PublishProcessor o = PublishProcessor.create(); + o.throttleLast(500, TimeUnit.MILLISECONDS, s, dropCallbackObserver::onNext).subscribe(subscriber); + + // send events with simulated time increments + s.advanceTimeTo(0, TimeUnit.MILLISECONDS); + o.onNext(1); // skip + o.onNext(2); // deliver + s.advanceTimeTo(501, TimeUnit.MILLISECONDS); + o.onNext(3); // skip + s.advanceTimeTo(600, TimeUnit.MILLISECONDS); + o.onNext(4); // skip + s.advanceTimeTo(700, TimeUnit.MILLISECONDS); + o.onNext(5); // skip + o.onNext(6); // deliver + s.advanceTimeTo(1001, TimeUnit.MILLISECONDS); + o.onNext(7); // deliver + s.advanceTimeTo(1501, TimeUnit.MILLISECONDS); + o.onComplete(); + + InOrder inOrder = inOrder(subscriber); + InOrder dropCallbackOrder = inOrder(dropCallbackObserver); + dropCallbackOrder.verify(dropCallbackObserver).onNext(1); + inOrder.verify(subscriber).onNext(2); + dropCallbackOrder.verify(dropCallbackObserver).onNext(3); + dropCallbackOrder.verify(dropCallbackObserver).onNext(4); + dropCallbackOrder.verify(dropCallbackObserver).onNext(5); + inOrder.verify(subscriber).onNext(6); + inOrder.verify(subscriber).onNext(7); + inOrder.verify(subscriber).onComplete(); + inOrder.verifyNoMoreInteractions(); + dropCallbackOrder.verifyNoMoreInteractions(); + } + @Test public void throttle() { Subscriber subscriber = TestHelper.mockSubscriber(); diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableThrottleWithTimeoutTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableThrottleWithTimeoutTests.java index f84d27a00d8..be94bf9d38c 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableThrottleWithTimeoutTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableThrottleWithTimeoutTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableWindowTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableWindowTests.java index f96a010728d..2ba648282fa 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableWindowTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableWindowTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/flowable/FlowableZipTests.java b/src/test/java/io/reactivex/rxjava3/flowable/FlowableZipTests.java index e1b2e2809b0..7f77992bfe3 100644 --- a/src/test/java/io/reactivex/rxjava3/flowable/FlowableZipTests.java +++ b/src/test/java/io/reactivex/rxjava3/flowable/FlowableZipTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/SubscribeWithTest.java b/src/test/java/io/reactivex/rxjava3/internal/SubscribeWithTest.java index e1b858507a0..a24562a8542 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/SubscribeWithTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/SubscribeWithTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/disposables/ArrayCompositeDisposableTest.java b/src/test/java/io/reactivex/rxjava3/internal/disposables/ArrayCompositeDisposableTest.java index 8871cc4e500..c0319dfd3ad 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/disposables/ArrayCompositeDisposableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/disposables/ArrayCompositeDisposableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/disposables/CancellableDisposableTest.java b/src/test/java/io/reactivex/rxjava3/internal/disposables/CancellableDisposableTest.java index 03f54c92189..ab40e7c03ce 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/disposables/CancellableDisposableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/disposables/CancellableDisposableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/disposables/DisposableHelperTest.java b/src/test/java/io/reactivex/rxjava3/internal/disposables/DisposableHelperTest.java index 0332b025565..a3102ea44f5 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/disposables/DisposableHelperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/disposables/DisposableHelperTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/disposables/EmptyDisposableTest.java b/src/test/java/io/reactivex/rxjava3/internal/disposables/EmptyDisposableTest.java index b66f27036ee..1f0d370dcd7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/disposables/EmptyDisposableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/disposables/EmptyDisposableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,7 +18,7 @@ import org.junit.Test; import io.reactivex.rxjava3.core.RxJavaTest; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.testsupport.TestHelper; public class EmptyDisposableTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/rxjava3/internal/disposables/ListCompositeDisposableTest.java b/src/test/java/io/reactivex/rxjava3/internal/disposables/ListCompositeDisposableTest.java index 0325d005004..1a0070e22de 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/disposables/ListCompositeDisposableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/disposables/ListCompositeDisposableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/functions/FunctionsTest.java b/src/test/java/io/reactivex/rxjava3/internal/functions/FunctionsTest.java index 72e188fe997..635fcc4472f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/functions/FunctionsTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/functions/FunctionsTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -39,12 +39,12 @@ public void utilityClass() { public void hashSetCallableEnum() { // inlined TestHelper.checkEnum due to access restrictions try { - Method m = Functions.HashSetCallable.class.getMethod("values"); + Method m = Functions.HashSetSupplier.class.getMethod("values"); m.setAccessible(true); - Method e = Functions.HashSetCallable.class.getMethod("valueOf", String.class); + Method e = Functions.HashSetSupplier.class.getMethod("valueOf", String.class); e.setAccessible(true); - for (Enum o : (Enum[])m.invoke(null)) { + for (Enum o : (Enum[])m.invoke(null)) { assertSame(o, e.invoke(null, o.name())); } diff --git a/src/test/java/io/reactivex/rxjava3/internal/functions/ObjectHelperTest.java b/src/test/java/io/reactivex/rxjava3/internal/functions/ObjectHelperTest.java index 16c182061d7..fb7e912da4d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/functions/ObjectHelperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/functions/ObjectHelperTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/fuseable/CancellableQueueFuseableTest.java b/src/test/java/io/reactivex/rxjava3/internal/fuseable/CancellableQueueFuseableTest.java new file mode 100644 index 00000000000..67144abea29 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/fuseable/CancellableQueueFuseableTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.fuseable; + +import static org.junit.Assert.*; +import org.junit.Test; + +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class CancellableQueueFuseableTest { + + @Test + public void offer() { + TestHelper.assertNoOffer(new CancellableQueueFuseable<>()); + } + + @Test + public void pollClear() throws Throwable { + CancellableQueueFuseable qs = new CancellableQueueFuseable<>(); + + assertNull(qs.poll()); + + qs.clear(); + assertNull(qs.poll()); + } + + @Test + public void cancel() { + CancellableQueueFuseable qs = new CancellableQueueFuseable<>(); + + assertFalse(qs.isDisposed()); + + qs.cancel(); + + assertTrue(qs.isDisposed()); + + qs.cancel(); + + assertTrue(qs.isDisposed()); + } + + @Test + public void dispose() { + CancellableQueueFuseable qs = new CancellableQueueFuseable<>(); + + assertFalse(qs.isDisposed()); + + qs.dispose(); + + assertTrue(qs.isDisposed()); + + qs.dispose(); + + assertTrue(qs.isDisposed()); + } + + @Test + public void cancel2() { + AbstractEmptyQueueFuseable qs = new AbstractEmptyQueueFuseable() { }; + + assertFalse(qs.isDisposed()); + + qs.cancel(); + } + + @Test + public void dispose2() { + AbstractEmptyQueueFuseable qs = new AbstractEmptyQueueFuseable() { }; + + assertFalse(qs.isDisposed()); + + qs.dispose(); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/CollectWithCollectorTckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/CollectWithCollectorTckTest.java index 99fb2dcff94..4745b9c8096 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/CollectWithCollectorTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/CollectWithCollectorTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/CompletableFromCompletionStageTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/CompletableFromCompletionStageTest.java index 3519cc54541..6e9bf78e1d9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/CompletableFromCompletionStageTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/CompletableFromCompletionStageTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/CompletableToCompletionStageTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/CompletableToCompletionStageTest.java index 91fdfb9cde6..8917b1c6754 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/CompletableToCompletionStageTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/CompletableToCompletionStageTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream0HTckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream0HTckTest.java index 57365f58578..e499ac1b9a5 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream0HTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream0HTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream0TckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream0TckTest.java index 232ded7321f..fa33b67ebfa 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream0TckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream0TckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream1HTckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream1HTckTest.java index aa65a19ca7b..ee1a27b5483 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream1HTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream1HTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream1TckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream1TckTest.java index 20e99b1ec14..21492d61b88 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream1TckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream1TckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream2HTckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream2HTckTest.java index 0c06e4de40b..14e44d69eee 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream2HTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream2HTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream2TckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream2TckTest.java index d799a720c9a..c42e6f7a80e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream2TckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlatMapStream2TckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableBlockingStreamTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableBlockingStreamTest.java index 2cf932f40ed..be49e2ed11f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableBlockingStreamTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableBlockingStreamTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableCollectWithCollectorTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableCollectWithCollectorTest.java index ecef7665e00..3a8a1d5b192 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableCollectWithCollectorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableCollectWithCollectorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFlatMapStreamTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFlatMapStreamTest.java index 548a66a7098..c865d35a526 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFlatMapStreamTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFlatMapStreamTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -274,7 +274,7 @@ protected void subscribeActual(Subscriber s) { } .flatMapStream(v -> Stream.of(1, 2), 1) .test(0) - .assertFailure(MissingBackpressureException.class); + .assertFailure(QueueOverflowException.class); TestHelper.assertUndeliverable(errors, 0, TestException.class); }); diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromCompletionStageTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromCompletionStageTest.java index 8a71bbd9b38..aebeea58b60 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromCompletionStageTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromCompletionStageTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromOptionalTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromOptionalTest.java index 6676bcee611..743dc0f5735 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromOptionalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromOptionalTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromStreamTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromStreamTest.java index 7d5f7a0a74e..57a8caf6bf6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromStreamTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromStreamTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,9 @@ import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; -import io.reactivex.rxjava3.internal.fuseable.*; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableMapOptionalTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableMapOptionalTest.java index 85fc8d75bef..fbffd790011 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableMapOptionalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableMapOptionalTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,10 +23,11 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; +import io.reactivex.rxjava3.internal.schedulers.ImmediateThinScheduler; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.processors.*; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class FlowableMapOptionalTest extends RxJavaTest { @@ -467,4 +468,20 @@ public void boundaryFusedMixedConditional() { .assertFusionMode(QueueFuseable.NONE) .assertResult(2, 4, 6, 8, 10); } + + @Test + public void conditionalFusionNoNPE() { + TestSubscriberEx ts = new TestSubscriberEx<>() + .setInitialFusionMode(QueueFuseable.ANY); + + Flowable.empty() + .observeOn(ImmediateThinScheduler.INSTANCE) + .filter(v -> true) + .mapOptional(Optional::of) + .filter(v -> true) + .subscribe(ts) + ; + + ts.assertResult(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableStageSubscriberOrDefaultTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableStageSubscriberOrDefaultTest.java index 882fd83dfb4..d63a81c8ef9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableStageSubscriberOrDefaultTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableStageSubscriberOrDefaultTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableStageSubscriberOrErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableStageSubscriberOrErrorTest.java index c34e4739fa8..763a1e04445 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableStageSubscriberOrErrorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FlowableStageSubscriberOrErrorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromCompletionStageTckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromCompletionStageTckTest.java index 2c48611cd99..6d2e9d21551 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromCompletionStageTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromCompletionStageTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromOptional0TckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromOptional0TckTest.java index 76c1246eb30..ff30aa4b2dc 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromOptional0TckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromOptional0TckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromOptional1TckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromOptional1TckTest.java index 27e596d708e..f6b56a582dc 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromOptional1TckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromOptional1TckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromStreamTckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromStreamTckTest.java index 06f3b02b979..a0995dad39a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromStreamTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/FromStreamTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MapOptionalTckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MapOptionalTckTest.java index b7cb4d97259..345159da4a1 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MapOptionalTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MapOptionalTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsFlowableTckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsFlowableTckTest.java index 94906fdd2f0..55e6778d3f9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsFlowableTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsFlowableTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsFlowableTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsFlowableTest.java index 8e1e75b8e05..d8377eac603 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsFlowableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsFlowableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -28,8 +28,9 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.subjects.MaybeSubject; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsObservableTest.java index dd0fb5c2edb..145112987db 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFlattenStreamAsObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,8 +27,9 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.subjects.MaybeSubject; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFromCompletionStageTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFromCompletionStageTest.java index 90ad2bc6261..552a4afc106 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFromCompletionStageTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFromCompletionStageTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFromOptionalTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFromOptionalTest.java index 4e09fea0b19..8af5faf5d70 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFromOptionalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeFromOptionalTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeMapOptionalTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeMapOptionalTest.java index e8b9f2aac30..a8adbcb6f8e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeMapOptionalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeMapOptionalTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeToCompletionStageTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeToCompletionStageTest.java index c6c83e68a3e..12e4ca5f1ea 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeToCompletionStageTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/MaybeToCompletionStageTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableBlockingStreamTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableBlockingStreamTest.java index b62bedb6f81..275b38a57b4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableBlockingStreamTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableBlockingStreamTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableCollectWithCollectorTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableCollectWithCollectorTest.java index 923a7dbaa3a..f18f42a3d0c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableCollectWithCollectorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableCollectWithCollectorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFlatMapStreamTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFlatMapStreamTest.java index 8341aa03dd1..5afcfa33ff8 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFlatMapStreamTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFlatMapStreamTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromCompletionStageTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromCompletionStageTest.java index 612ab0724b9..2be5ecf510d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromCompletionStageTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromCompletionStageTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromOptionalTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromOptionalTest.java index e2e4059e705..5fbeb1f2ff5 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromOptionalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromOptionalTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromStreamTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromStreamTest.java index 6074e54689d..2b943e5338e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromStreamTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableFromStreamTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,8 +26,10 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.SimpleQueue; import io.reactivex.rxjava3.testsupport.*; public class ObservableFromStreamTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableMapOptionalTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableMapOptionalTest.java index ba38417b125..1b0a7f0a7d4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableMapOptionalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableMapOptionalTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,7 +23,7 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.subjects.*; import io.reactivex.rxjava3.testsupport.TestHelper; diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableStageSubscriberOrDefaultTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableStageSubscriberOrDefaultTest.java index 9b02622c9b8..f652c9b3276 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableStageSubscriberOrDefaultTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableStageSubscriberOrDefaultTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableStageSubscriberOrErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableStageSubscriberOrErrorTest.java index d8e6fbe9185..5646fc3d597 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableStageSubscriberOrErrorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ObservableStageSubscriberOrErrorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelCollectorTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelCollectorTest.java index 8e558a00489..9d0fc09f62e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelCollectorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelCollectorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -148,6 +148,7 @@ public Set characteristics() { } @Test + @SuppressUndeliverable public void collectorCombinerCrash() { Flowable.range(1, 5) .parallel() diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelFlatMapStreamTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelFlatMapStreamTest.java index 0f39d4c8421..f1d34491d50 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelFlatMapStreamTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelFlatMapStreamTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapOptionalTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapOptionalTest.java index 67cab4087eb..ca7385b7f64 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapOptionalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapOptionalTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapTryOptionalTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapTryOptionalTest.java index b7cae915684..459b3f884a8 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapTryOptionalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/ParallelMapTryOptionalTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsFlowableTckTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsFlowableTckTest.java index 509429d4afe..53c42065105 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsFlowableTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsFlowableTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsFlowableTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsFlowableTest.java index 72dc8fb2393..6e74b423704 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsFlowableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsFlowableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -28,8 +28,9 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.subjects.SingleSubject; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsObservableTest.java index 2b3a624d509..2c50634823f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFlattenStreamAsObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,8 +27,9 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.subjects.SingleSubject; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFromCompletionStageTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFromCompletionStageTest.java index 7adb3664be0..c62996e5868 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFromCompletionStageTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleFromCompletionStageTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleMapOptionalTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleMapOptionalTest.java index b8ab17a17c0..56bc5dbae51 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleMapOptionalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleMapOptionalTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleToCompletionStageTest.java b/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleToCompletionStageTest.java index 2560c68ed84..2709b6ee40f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleToCompletionStageTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/jdk8/SingleToCompletionStageTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/BasicFuseableObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/BasicFuseableObserverTest.java index 1764ea6a474..f48d0a574e7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/BasicFuseableObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/BasicFuseableObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/BasicQueueDisposableTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/BasicQueueDisposableTest.java index e5ed0fb605d..d9bf9947460 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/BasicQueueDisposableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/BasicQueueDisposableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/BlockingFirstObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/BlockingFirstObserverTest.java index 0b33e6ddfff..3a65016574c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/BlockingFirstObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/BlockingFirstObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/BlockingMultiObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/BlockingMultiObserverTest.java index b9ec5d276bd..0ea5b468ac0 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/BlockingMultiObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/BlockingMultiObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/BlockingObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/BlockingObserverTest.java index 1a07bdf9073..cbf8b7ce7c5 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/BlockingObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/BlockingObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/CallbackCompletableObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/CallbackCompletableObserverTest.java index e52ab8c023a..46c4cc44636 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/CallbackCompletableObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/CallbackCompletableObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,7 +24,7 @@ public final class CallbackCompletableObserverTest extends RxJavaTest { @Test public void emptyActionShouldReportNoCustomOnError() { - CallbackCompletableObserver o = new CallbackCompletableObserver(Functions.EMPTY_ACTION); + CallbackCompletableObserver o = new CallbackCompletableObserver(Functions.ON_ERROR_MISSING, Functions.EMPTY_ACTION); assertFalse(o.hasCustomOnError()); } diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/CompletableConsumersTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/CompletableConsumersTest.java new file mode 100644 index 00000000000..eb17ead3db0 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/CompletableConsumersTest.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +/* + * Copyright 2016-2019 David Karnok + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.util.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.exceptions.CompositeException; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.observers.LambdaConsumerIntrospection; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.subjects.CompletableSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class CompletableConsumersTest implements Consumer, Action { + + final CompositeDisposable composite = new CompositeDisposable(); + + final CompletableSubject processor = CompletableSubject.create(); + + final List events = new ArrayList<>(); + + @Override + public void run() throws Exception { + events.add("OnComplete"); + } + + @Override + public void accept(Object t) throws Exception { + events.add(t); + } + + @Test + public void onErrorNormal() { + + processor.subscribe(this, this, composite); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onComplete(); + + assertEquals(0, composite.size()); + + assertEquals(Arrays.asList("OnComplete"), events); + + } + + @Test + public void onErrorError() { + + Disposable d = processor.subscribe(this, this, composite); + + assertTrue(d.getClass().toString(), ((LambdaConsumerIntrospection)d).hasCustomOnError()); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onError(new IOException()); + + assertTrue(events.toString(), events.get(0) instanceof IOException); + + assertEquals(0, composite.size()); + } + + @Test + public void onCompleteNormal() { + + processor.subscribe(this, this, composite); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onComplete(); + + assertEquals(0, composite.size()); + + assertEquals(Arrays.asList("OnComplete"), events); + + } + + @Test + public void onCompleteError() { + + processor.subscribe(this, this, composite); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onError(new IOException()); + + assertTrue(events.toString(), events.get(0) instanceof IOException); + + assertEquals(0, composite.size()); + } + + @Test + public void onCompleteDispose() { + + Disposable d = processor.subscribe(this, this, composite); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + assertFalse(d.isDisposed()); + + d.dispose(); + d.dispose(); + + assertTrue(d.isDisposed()); + + assertEquals(0, composite.size()); + + assertFalse(processor.hasObservers()); + } + + @Test + public void onErrorCrash() { + List errors = TestHelper.trackPluginErrors(); + try { + processor.subscribe(this, t -> { + throw new IOException(t); + }, composite); + + processor.onError(new IllegalArgumentException()); + + assertTrue(events.toString(), events.isEmpty()); + + TestHelper.assertError(errors, 0, CompositeException.class); + List inners = TestHelper.compositeList(errors.get(0)); + TestHelper.assertError(inners, 0, IllegalArgumentException.class); + TestHelper.assertError(inners, 1, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void onCompleteCrash() { + List errors = TestHelper.trackPluginErrors(); + try { + processor.subscribe(new Action() { + @Override + public void run() throws Exception { + throw new IOException(); + } + }, this, composite); + + processor.onComplete(); + + assertTrue(events.toString(), events.isEmpty()); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void badSource() { + List errors = TestHelper.trackPluginErrors(); + try { + new Completable() { + @Override + protected void subscribeActual( + CompletableObserver observer) { + observer.onSubscribe(Disposable.empty()); + observer.onComplete(); + + observer.onSubscribe(Disposable.empty()); + observer.onComplete(); + observer.onError(new IOException()); + } + }.subscribe(this, this, composite); + + assertEquals(Arrays.asList("OnComplete"), events); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/ConsumerSingleObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/ConsumerSingleObserverTest.java index 5e264bc4d7d..f6ebdb498f5 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/ConsumerSingleObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/ConsumerSingleObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/DeferredScalarDisposableTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/DeferredScalarDisposableTest.java new file mode 100644 index 00000000000..19c5b7db273 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/DeferredScalarDisposableTest.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.RxJavaTest; +import io.reactivex.rxjava3.observers.TestObserver; + +public class DeferredScalarDisposableTest extends RxJavaTest { + + @Test + public void tryDispose() { + TestObserver to = new TestObserver<>(); + + DeferredScalarDisposable d = new DeferredScalarDisposable<>(to); + to.onSubscribe(d); + + assertTrue(d.tryDispose()); + assertFalse(d.tryDispose()); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/DeferredScalarObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/DeferredScalarObserverTest.java index e9668c81cea..165de9b4676 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/DeferredScalarObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/DeferredScalarObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,8 +22,9 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.*; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/DisposableLambdaObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/DisposableLambdaObserverTest.java index 964301f6e43..294892507b4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/DisposableLambdaObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/DisposableLambdaObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/EmptyCompletableObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/EmptyCompletableObserverTest.java index e8733263754..c58de8f0f95 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/EmptyCompletableObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/EmptyCompletableObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/FutureMultiObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/FutureMultiObserverTest.java new file mode 100644 index 00000000000..7499b99ca18 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/FutureMultiObserverTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import static org.junit.Assert.*; +import org.junit.Test; + +import io.reactivex.rxjava3.core.RxJavaTest; +import io.reactivex.rxjava3.disposables.Disposable; + +public class FutureMultiObserverTest extends RxJavaTest { + + @Test + public void cancelBeforeOnSubscribe() { + FutureMultiObserver f = new FutureMultiObserver<>(); + + assertTrue(f.cancel(true)); + + Disposable d = Disposable.empty(); + + f.onSubscribe(d); + + assertTrue(d.isDisposed()); + } + + @Test + public void onCompleteJustAfterDispose() { + FutureMultiObserver f = new FutureMultiObserver<>(); + Disposable d = Disposable.empty(); + f.onSubscribe(d); + assertTrue(f.cancel(true)); + + f.onComplete(); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/FutureObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/FutureObserverTest.java index a4a8f353c2b..8c475eb0383 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/FutureObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/FutureObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,11 +22,9 @@ import org.junit.*; import io.reactivex.rxjava3.core.RxJavaTest; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.subscribers.FutureSubscriber; -import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.testsupport.TestHelper; @@ -157,7 +155,7 @@ public void onSubscribe() throws Exception { @Test public void cancelRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { - final FutureSubscriber fo = new FutureSubscriber<>(); + final FutureObserver fo = new FutureObserver<>(); Runnable r = new Runnable() { @Override @@ -188,7 +186,7 @@ public void onErrorCancelRace() { RxJavaPlugins.setErrorHandler(Functions.emptyConsumer()); try { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { - final FutureSubscriber fo = new FutureSubscriber<>(); + final FutureObserver fo = new FutureObserver<>(); final TestException ex = new TestException(); @@ -218,10 +216,10 @@ public void onCompleteCancelRace() { RxJavaPlugins.setErrorHandler(Functions.emptyConsumer()); try { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { - final FutureSubscriber fo = new FutureSubscriber<>(); + final FutureObserver fo = new FutureObserver<>(); if (i % 3 == 0) { - fo.onSubscribe(new BooleanSubscription()); + fo.onSubscribe(Disposable.empty()); } if (i % 2 == 0) { @@ -288,6 +286,22 @@ public void onCompleteOnError() throws Exception { } } + @Test + public void onNextCompleteOnError() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + fo.onNext(1); + fo.onComplete(); + fo.onError(new TestException("One")); + + assertEquals((Integer)1, fo.get(5, TimeUnit.MILLISECONDS)); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + } finally { + RxJavaPlugins.reset(); + } + } + @Test public void cancelOnError() throws Exception { List errors = TestHelper.trackPluginErrors(); @@ -364,4 +378,22 @@ public void getTimedOut() throws Exception { assertEquals(timeoutMessage(1, TimeUnit.NANOSECONDS), expected.getMessage()); } } + + @Test + public void cancelOnSubscribeRace() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + final FutureObserver fo = new FutureObserver<>(); + + Runnable r = new Runnable() { + @Override + public void run() { + fo.cancel(false); + } + }; + + Disposable d = Disposable.empty(); + + TestHelper.race(r, () -> fo.onSubscribe(d)); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/FutureSingleObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/FutureSingleObserverTest.java index eb11be24c3b..db8b414347a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/FutureSingleObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/FutureSingleObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/InnerQueuedObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/InnerQueuedObserverTest.java new file mode 100644 index 00000000000..549c72534ad --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/InnerQueuedObserverTest.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.RxJavaTest; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class InnerQueuedObserverTest extends RxJavaTest { + + @Test + public void dispose() { + TestHelper.checkDisposed(new InnerQueuedObserver<>(null, 1)); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/LambdaObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/LambdaObserverTest.java index c19b6ff2dbb..7ce43074191 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/LambdaObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/LambdaObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/MaybeConsumersTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/MaybeConsumersTest.java new file mode 100644 index 00000000000..92b32c000e6 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/MaybeConsumersTest.java @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +/* + * Copyright 2016-2019 David Karnok + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.util.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.exceptions.CompositeException; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.observers.LambdaConsumerIntrospection; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.subjects.MaybeSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class MaybeConsumersTest implements Consumer, Action { + + final CompositeDisposable composite = new CompositeDisposable(); + + final MaybeSubject processor = MaybeSubject.create(); + + final List events = new ArrayList<>(); + + @Override + public void run() throws Exception { + events.add("OnComplete"); + } + + @Override + public void accept(Object t) throws Exception { + events.add(t); + } + + static Disposable subscribeAutoDispose(Maybe source, CompositeDisposable composite, + Consumer onSuccess, Consumer onError, Action onComplete) { + return source.subscribe(onSuccess, onError, onComplete, composite); + } + + @Test + public void onSuccessNormal() { + + Disposable d = subscribeAutoDispose(processor, composite, this, Functions.ON_ERROR_MISSING, () -> { }); + + assertFalse(d.getClass().toString(), ((LambdaConsumerIntrospection)d).hasCustomOnError()); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onSuccess(1); + + assertEquals(0, composite.size()); + + assertEquals(Arrays.asList(1), events); + + } + + @Test + public void onErrorNormal() { + + subscribeAutoDispose(processor, composite, this, this, this); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onSuccess(1); + + assertEquals(0, composite.size()); + + assertEquals(Arrays.asList(1), events); + + } + + @Test + public void onErrorError() { + + Disposable d = subscribeAutoDispose(processor, composite, this, this, this); + + assertTrue(d.getClass().toString(), ((LambdaConsumerIntrospection)d).hasCustomOnError()); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onError(new IOException()); + + assertTrue(events.toString(), events.get(0) instanceof IOException); + + assertEquals(0, composite.size()); + } + + @Test + public void onCompleteNormal() { + + subscribeAutoDispose(processor, composite, this, this, this); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onComplete(); + + assertEquals(0, composite.size()); + + assertEquals(Arrays.asList("OnComplete"), events); + + } + + @Test + public void onCompleteError() { + + subscribeAutoDispose(processor, composite, this, this, this); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onError(new IOException()); + + assertTrue(events.toString(), events.get(0) instanceof IOException); + + assertEquals(0, composite.size()); + } + + @Test + public void onCompleteDispose() { + + Disposable d = subscribeAutoDispose(processor, composite, this, this, this); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + assertFalse(d.isDisposed()); + + d.dispose(); + d.dispose(); + + assertTrue(d.isDisposed()); + + assertEquals(0, composite.size()); + + assertFalse(processor.hasObservers()); + } + + @Test + public void onSuccessCrash() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose(processor, composite, new Consumer() { + @Override + public void accept(Object t) throws Exception { + throw new IOException(); + } + }, this, this); + + processor.onSuccess(1); + + assertTrue(events.toString(), events.isEmpty()); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void onErrorCrash() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose(processor, composite, this, new Consumer() { + @Override + public void accept(Throwable t) throws Exception { + throw new IOException(t); + } + }, this); + + processor.onError(new IllegalArgumentException()); + + assertTrue(events.toString(), events.isEmpty()); + + TestHelper.assertError(errors, 0, CompositeException.class); + List inners = TestHelper.compositeList(errors.get(0)); + TestHelper.assertError(inners, 0, IllegalArgumentException.class); + TestHelper.assertError(inners, 1, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void onCompleteCrash() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose(processor, composite, this, this, new Action() { + @Override + public void run() throws Exception { + throw new IOException(); + } + }); + + processor.onComplete(); + + assertTrue(events.toString(), events.isEmpty()); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void badSource() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose( + new Maybe() { + @Override + protected void subscribeActual( + MaybeObserver observer) { + observer.onSubscribe(Disposable.empty()); + observer.onComplete(); + + observer.onSubscribe(Disposable.empty()); + observer.onSuccess(2); + observer.onComplete(); + observer.onError(new IOException()); + } + }, composite, this, this, this + ); + + assertEquals(Arrays.asList("OnComplete"), events); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/ObservableConsumersTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/ObservableConsumersTest.java new file mode 100644 index 00000000000..b5d26340e75 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/ObservableConsumersTest.java @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +/* + * Copyright 2016-2019 David Karnok + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.util.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.observers.LambdaConsumerIntrospection; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.subjects.PublishSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class ObservableConsumersTest implements Consumer, Action { + + final CompositeDisposable composite = new CompositeDisposable(); + + final PublishSubject processor = PublishSubject.create(); + + final List events = new ArrayList<>(); + + @Override + public void run() throws Exception { + events.add("OnComplete"); + } + + @Override + public void accept(Object t) throws Exception { + events.add(t); + } + + static Disposable subscribeAutoDispose(Observable source, CompositeDisposable composite, + Consumer onNext, Consumer onError, Action onComplete) { + return source.subscribe(onNext, onError, onComplete, composite); + } + + @Test + public void onNextNormal() { + + Disposable d = subscribeAutoDispose(processor, composite, this, Functions.ON_ERROR_MISSING, () -> { }); + + assertFalse(d.getClass().toString(), ((LambdaConsumerIntrospection)d).hasCustomOnError()); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onNext(1); + + assertTrue(composite.size() > 0); + + assertEquals(Arrays.asList(1), events); + + processor.onComplete(); + + assertEquals(Arrays.asList(1), events); + + assertEquals(0, composite.size()); + } + + @Test + public void onErrorNormal() { + + subscribeAutoDispose(processor, composite, this, Functions.ON_ERROR_MISSING, () -> { }); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onNext(1); + + assertTrue(composite.size() > 0); + + assertEquals(Arrays.asList(1), events); + + processor.onComplete(); + + assertEquals(Arrays.asList(1), events); + + assertEquals(0, composite.size()); + } + + @Test + public void onErrorError() { + + Disposable d = subscribeAutoDispose(processor, composite, this, this, this); + + assertTrue(d.getClass().toString(), ((LambdaConsumerIntrospection)d).hasCustomOnError()); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onNext(1); + + assertTrue(composite.size() > 0); + + assertEquals(Arrays.asList(1), events); + + processor.onError(new IOException()); + + assertEquals(events.toString(), 1, events.get(0)); + assertTrue(events.toString(), events.get(1) instanceof IOException); + + assertEquals(0, composite.size()); + } + + @Test + public void onCompleteNormal() { + + subscribeAutoDispose(processor, composite, this, this, this); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onNext(1); + + assertTrue(composite.size() > 0); + + assertEquals(Arrays.asList(1), events); + + processor.onComplete(); + + assertEquals(Arrays.asList(1, "OnComplete"), events); + + assertEquals(0, composite.size()); + } + + @Test + public void onCompleteError() { + + subscribeAutoDispose(processor, composite, this, this, this); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onNext(1); + + assertTrue(composite.size() > 0); + + assertEquals(Arrays.asList(1), events); + + processor.onError(new IOException()); + + assertEquals(events.toString(), 1, events.get(0)); + assertTrue(events.toString(), events.get(1) instanceof IOException); + + assertEquals(0, composite.size()); + } + + @Test + public void onCompleteDispose() { + + Disposable d = subscribeAutoDispose(processor, composite, this, this, this); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + assertFalse(d.isDisposed()); + + d.dispose(); + d.dispose(); + + assertTrue(d.isDisposed()); + + assertEquals(0, composite.size()); + + assertFalse(processor.hasObservers()); + } + + @Test + public void onNextCrash() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose(processor, composite, new Consumer() { + @Override + public void accept(Object t) throws Exception { + throw new IOException(); + } + }, this, this); + + processor.onNext(1); + + assertTrue(errors.toString(), errors.isEmpty()); + + assertTrue(events.toString(), events.get(0) instanceof IOException); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void onNextCrashOnError() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose(processor, composite, this, new Consumer() { + @Override + public void accept(Throwable t) throws Exception { + throw new IOException(t); + } + }, this); + + processor.onError(new IllegalArgumentException()); + + assertTrue(events.toString(), events.isEmpty()); + + TestHelper.assertError(errors, 0, CompositeException.class); + List inners = TestHelper.compositeList(errors.get(0)); + TestHelper.assertError(inners, 0, IllegalArgumentException.class); + TestHelper.assertError(inners, 1, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void onNextCrashNoError() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose(processor, composite, t -> { + throw new IOException(); + }, Functions.ON_ERROR_MISSING, () -> { }); + + processor.onNext(1); + + assertTrue(events.toString(), events.isEmpty()); + + TestHelper.assertError(errors, 0, OnErrorNotImplementedException.class); + assertTrue(errors.get(0).getCause() instanceof IOException); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void onCompleteCrash() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose(processor, composite, this, this, new Action() { + @Override + public void run() throws Exception { + throw new IOException(); + } + }); + + processor.onNext(1); + processor.onComplete(); + + assertEquals(Arrays.asList(1), events); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void badSource() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose( + new Observable() { + @Override + protected void subscribeActual( + Observer observer) { + observer.onSubscribe(Disposable.empty()); + observer.onNext(1); + observer.onComplete(); + + observer.onSubscribe(Disposable.empty()); + observer.onNext(2); + observer.onComplete(); + observer.onError(new IOException()); + } + }, composite, this, this, this + ); + + assertEquals(Arrays.asList(1, "OnComplete"), events); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/QueueDrainObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/QueueDrainObserverTest.java index 9afd31e95f1..eb2523a4662 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/observers/QueueDrainObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/QueueDrainObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,8 +17,8 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.*; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.SpscArrayQueue; import io.reactivex.rxjava3.testsupport.TestHelper; public class QueueDrainObserverTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/rxjava3/internal/observers/SingleConsumersTest.java b/src/test/java/io/reactivex/rxjava3/internal/observers/SingleConsumersTest.java new file mode 100644 index 00000000000..a840d8f71aa --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/observers/SingleConsumersTest.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +/* + * Copyright 2016-2019 David Karnok + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.reactivex.rxjava3.internal.observers; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.util.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.exceptions.CompositeException; +import io.reactivex.rxjava3.functions.Consumer; +import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.observers.LambdaConsumerIntrospection; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.subjects.SingleSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class SingleConsumersTest implements Consumer { + + final CompositeDisposable composite = new CompositeDisposable(); + + final SingleSubject processor = SingleSubject.create(); + + final List events = new ArrayList<>(); + + @Override + public void accept(Object t) throws Exception { + events.add(t); + } + + static Disposable subscribeAutoDispose(Single source, CompositeDisposable composite, + Consumer onSuccess, Consumer onError) { + return source.subscribe(onSuccess, onError, composite); + } + + @Test + public void onSuccessNormal() { + + Disposable d = subscribeAutoDispose(processor, composite, this, Functions.ON_ERROR_MISSING); + + assertFalse(d.getClass().toString(), ((LambdaConsumerIntrospection)d).hasCustomOnError()); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onSuccess(1); + + assertEquals(0, composite.size()); + + assertEquals(Arrays.asList(1), events); + + } + + @Test + public void onErrorNormal() { + + subscribeAutoDispose(processor, composite, this, this); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onSuccess(1); + + assertEquals(0, composite.size()); + + assertEquals(Arrays.asList(1), events); + + } + + @Test + public void onErrorError() { + + Disposable d = subscribeAutoDispose(processor, composite, this, this); + + assertTrue(d.getClass().toString(), ((LambdaConsumerIntrospection)d).hasCustomOnError()); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onError(new IOException()); + + assertTrue(events.toString(), events.get(0) instanceof IOException); + + assertEquals(0, composite.size()); + } + + @Test + public void onSuccessCrash() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose(processor, composite, new Consumer() { + @Override + public void accept(Object t) throws Exception { + throw new IOException(); + } + }, this); + + processor.onSuccess(1); + + assertTrue(events.toString(), events.isEmpty()); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void onErrorCrash() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose(processor, composite, this, new Consumer() { + @Override + public void accept(Throwable t) throws Exception { + throw new IOException(t); + } + }); + + processor.onError(new IllegalArgumentException()); + + assertTrue(events.toString(), events.isEmpty()); + + TestHelper.assertError(errors, 0, CompositeException.class); + List inners = TestHelper.compositeList(errors.get(0)); + TestHelper.assertError(inners, 0, IllegalArgumentException.class); + TestHelper.assertError(inners, 1, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void badSource() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose( + new Single() { + @Override + protected void subscribeActual( + SingleObserver observer) { + observer.onSubscribe(Disposable.empty()); + observer.onSuccess(1); + + observer.onSubscribe(Disposable.empty()); + observer.onSuccess(2); + observer.onError(new IOException()); + } + }, composite, this, this + ); + + assertEquals(Arrays.asList(1), events); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAmbTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAmbTest.java index 60c69b5f204..0c9971017b6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAmbTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAmbTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenCompletableabTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenCompletableTest.java similarity index 95% rename from src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenCompletableabTest.java rename to src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenCompletableTest.java index c6b201be514..070fa8cb4dd 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenCompletableabTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,13 +27,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.testsupport.TestHelper; -public class CompletableAndThenCompletableabTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void andThenCompletableCompleteNull() { - Completable.complete() - .andThen((Completable) null); - } - +public class CompletableAndThenCompletableTest extends RxJavaTest { @Test public void andThenCompletableCompleteComplete() { Completable.complete() @@ -108,7 +102,7 @@ public void run() { .andThen(Completable.complete()) .test(true) .assertEmpty(); - assertEquals(1, completableRunCount.get()); + assertEquals(0, completableRunCount.get()); } @Test @@ -183,4 +177,9 @@ public void run() throws Exception { assertFalse("The second Completable was interrupted!", interrupted[0]); } } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeCompletable(c -> c.andThen(c)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenTest.java index 41656dbf339..943d44b9f27 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAndThenTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,12 +19,6 @@ import io.reactivex.rxjava3.testsupport.TestHelper; public class CompletableAndThenTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void andThenMaybeNull() { - Completable.complete() - .andThen((Maybe) null); - } - @Test public void andThenMaybeCompleteValue() { Completable.complete() diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAwaitTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAwaitTest.java index b7d6d61ea31..b614e2d79ea 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAwaitTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableAwaitTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableBlockingSubscribeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableBlockingSubscribeTest.java new file mode 100644 index 00000000000..a84f78ad73c --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableBlockingSubscribeTest.java @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.completable; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Completable; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class CompletableBlockingSubscribeTest { + + @Test + public void noArgComplete() { + Completable.complete() + .blockingSubscribe(); + } + + @Test + public void noArgCompleteAsync() { + Completable.complete() + .delay(100, TimeUnit.MILLISECONDS) + .blockingSubscribe(); + } + + @Test + public void noArgError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Completable.error(new TestException()) + .blockingSubscribe(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void noArgErrorAsync() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Completable.error(new TestException()) + .delay(100, TimeUnit.MILLISECONDS, Schedulers.computation(), true) + .blockingSubscribe(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void oneArgComplete() throws Throwable { + Action action = mock(Action.class); + + Completable.complete() + .blockingSubscribe(action); + + verify(action).run(); + } + + @Test + public void oneArgCompleteAsync() throws Throwable { + Action action = mock(Action.class); + + Completable.complete() + .delay(50, TimeUnit.MILLISECONDS) + .blockingSubscribe(action); + + verify(action).run(); + } + + @Test + public void oneArgCompleteFails() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Action action = mock(Action.class); + doThrow(new TestException()).when(action).run(); + + Completable.complete() + .blockingSubscribe(action); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(action).run(); + }); + } + + @Test + public void oneArgError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Action action = mock(Action.class); + + Completable.error(new TestException()) + .blockingSubscribe(action); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(action, never()).run(); + }); + } + + @Test + public void oneArgErrorAsync() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Action action = mock(Action.class); + + Completable.error(new TestException()) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation(), true) + .blockingSubscribe(action); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(action, never()).run(); + }); + } + + @Test + public void twoArgComplete() throws Throwable { + Action action = mock(Action.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Completable.complete() + .blockingSubscribe(action, consumer); + + verify(action).run(); + verify(consumer, never()).accept(any()); + } + + @Test + public void twoArgCompleteAsync() throws Throwable { + Action action = mock(Action.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Completable.complete() + .delay(50, TimeUnit.MILLISECONDS) + .blockingSubscribe(action, consumer); + + verify(action).run(); + verify(consumer, never()).accept(any()); + } + + @Test + public void twoArgCompleteFails() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Action action = mock(Action.class); + doThrow(new TestException()).when(action).run(); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Completable.complete() + .blockingSubscribe(action, consumer); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(action).run(); + verify(consumer, never()).accept(any()); + }); + } + + @Test + public void twoArgError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Action action = mock(Action.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Completable.error(new TestException()) + .blockingSubscribe(action, consumer); + + assertTrue("" + errors, errors.isEmpty()); + + verify(action, never()).run(); + verify(consumer).accept(any(TestException.class)); + }); + } + + @Test + public void twoArgErrorAsync() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Action action = mock(Action.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Completable.error(new TestException()) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation(), true) + .blockingSubscribe(action, consumer); + + assertTrue("" + errors, errors.isEmpty()); + + verify(action, never()).run(); + verify(consumer).accept(any(TestException.class)); + }); + } + + @Test + public void twoArgErrorFails() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Action action = mock(Action.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + doThrow(new TestException()).when(consumer).accept(any()); + + Completable.error(new TestException()) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation(), true) + .blockingSubscribe(action, consumer); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(action, never()).run(); + verify(consumer).accept(any(TestException.class)); + }); + } + + @Test + public void twoArgInterrupted() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Action onDispose = mock(Action.class); + + Action action = mock(Action.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Thread.currentThread().interrupt(); + + Completable.never() + .doOnDispose(onDispose) + .blockingSubscribe(action, consumer); + + assertTrue("" + errors, errors.isEmpty()); + + verify(onDispose).run(); + verify(action, never()).run(); + verify(consumer).accept(any(InterruptedException.class)); + }); + } + + @Test + public void observerComplete() { + TestObserver to = new TestObserver<>(); + + Completable.complete() + .blockingSubscribe(to); + + to.assertResult(); + } + + @Test + public void observerCompleteAsync() { + TestObserver to = new TestObserver<>(); + + Completable.complete() + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation(), true) + .blockingSubscribe(to); + + to.assertResult(); + } + + @Test + public void observerError() { + TestObserver to = new TestObserver<>(); + + Completable.error(new TestException()) + .blockingSubscribe(to); + + to.assertFailure(TestException.class); + } + + @Test + public void observerErrorAsync() { + TestObserver to = new TestObserver<>(); + + Completable.error(new TestException()) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation(), true) + .blockingSubscribe(to); + + to.assertFailure(TestException.class); + } + + @Test + public void observerDispose() throws Throwable { + Action onDispose = mock(Action.class); + + TestObserver to = new TestObserver<>(); + to.dispose(); + + Completable.never() + .doOnDispose(onDispose) + .blockingSubscribe(to); + + to.assertEmpty(); + + verify(onDispose).run(); + } + + @Test + public void ovserverInterrupted() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Action onDispose = mock(Action.class); + + TestObserver to = new TestObserver<>(); + + Thread.currentThread().interrupt(); + + Completable.never() + .doOnDispose(onDispose) + .blockingSubscribe(to); + + assertTrue("" + errors, errors.isEmpty()); + + verify(onDispose).run(); + to.assertFailure(InterruptedException.class); + }); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCacheTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCacheTest.java index fd286681c85..3e6193a2e92 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCacheTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCacheTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatArrayDelayErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatArrayDelayErrorTest.java new file mode 100644 index 00000000000..418afc70ccf --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatArrayDelayErrorTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.completable; + +import static org.mockito.Mockito.*; +import org.junit.Test; + +import io.reactivex.rxjava3.core.Completable; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.Action; + +public class CompletableConcatArrayDelayErrorTest { + + @Test + public void normal() throws Throwable { + Action action1 = mock(Action.class); + Action action2 = mock(Action.class); + + Completable.concatArrayDelayError( + Completable.fromAction(action1), + Completable.error(new TestException()), + Completable.fromAction(action2) + ) + .test() + .assertFailure(TestException.class); + + verify(action1).run(); + + verify(action2).run(); + } + +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatDelayErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatDelayErrorTest.java new file mode 100644 index 00000000000..8a9f9477d83 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatDelayErrorTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.completable; + +import static org.mockito.Mockito.*; + +import java.util.Arrays; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.Action; + +public class CompletableConcatDelayErrorTest { + + @Test + public void normalIterable() throws Throwable { + Action action1 = mock(Action.class); + Action action2 = mock(Action.class); + + Completable.concatDelayError(Arrays.asList( + Completable.fromAction(action1), + Completable.error(new TestException()), + Completable.fromAction(action2) + )) + .test() + .assertFailure(TestException.class); + + verify(action1).run(); + + verify(action2).run(); + } + + @Test + public void normalPublisher() throws Throwable { + Action action1 = mock(Action.class); + Action action2 = mock(Action.class); + + Completable.concatDelayError(Flowable.fromArray( + Completable.fromAction(action1), + Completable.error(new TestException()), + Completable.fromAction(action2) + )) + .test() + .assertFailure(TestException.class); + + verify(action1).run(); + + verify(action2).run(); + } + + @Test + public void normalPublisherPrefetch() throws Throwable { + Action action1 = mock(Action.class); + Action action2 = mock(Action.class); + + Completable.concatDelayError(Flowable.fromArray( + Completable.fromAction(action1), + Completable.error(new TestException()), + Completable.fromAction(action2) + ), 1) + .test() + .assertFailure(TestException.class); + + verify(action1).run(); + + verify(action2).run(); + } + +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatTest.java index b41086ce3be..11bc1a9b064 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableConcatTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -52,9 +52,9 @@ public void subscribe(Subscriber s) { }), 1 ) .test() - .assertFailure(MissingBackpressureException.class); + .assertFailure(QueueOverflowException.class); - TestHelper.assertError(errors, 0, MissingBackpressureException.class); + TestHelper.assertError(errors, 0, QueueOverflowException.class); } finally { RxJavaPlugins.reset(); } @@ -300,4 +300,9 @@ public void run() throws Exception { assertFalse("The second Completable was interrupted!", interrupted[0]); } } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowableToCompletable(f -> Completable.concat(f)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCreateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCreateTest.java index 2ee2550872d..bda1166ef92 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCreateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableCreateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -29,11 +29,6 @@ public class CompletableCreateTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void nullArgument() { - Completable.create(null); - } - @Test public void basic() { List errors = TestHelper.trackPluginErrors(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDelaySubscriptionTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDelaySubscriptionTest.java index d467d8e2cfa..6e524eff27d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDelaySubscriptionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDelaySubscriptionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDelayTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDelayTest.java index 94e34fe7285..c84972863db 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDelayTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDelayTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDetachTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDetachTest.java index b5b52b67c28..5373499d301 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDetachTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDetachTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDisposeOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDisposeOnTest.java index 32b5a85aa98..73a4e58c772 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDisposeOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDisposeOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ import io.reactivex.rxjava3.functions.Action; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.schedulers.TestScheduler; +import io.reactivex.rxjava3.schedulers.*; import io.reactivex.rxjava3.subjects.PublishSubject; import io.reactivex.rxjava3.testsupport.TestHelper; @@ -138,4 +138,9 @@ public void run() throws Exception { assertEquals(0, call[0]); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeCompletable(c -> c.unsubscribeOn(Schedulers.computation())); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoFinallyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoFinallyTest.java index cd0df19aaf0..14bd307b379 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoFinallyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoFinallyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -65,11 +65,6 @@ public Completable apply(Completable f) throws Exception { }); } - @Test(expected = NullPointerException.class) - public void nullAction() { - Completable.complete().doFinally(null); - } - @Test public void actionThrows() { List errors = TestHelper.trackPluginErrors(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoOnLifecycleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoOnLifecycleTest.java new file mode 100644 index 00000000000..1f66038f19f --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoOnLifecycleTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.completable; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.subjects.CompletableSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class CompletableDoOnLifecycleTest extends RxJavaTest { + + @Test + public void empty() throws Throwable { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + Completable.complete() + .doOnLifecycle(onSubscribe, onDispose) + .test() + .assertResult(); + + verify(onSubscribe).accept(any()); + verify(onDispose, never()).run(); + } + + @Test + public void error() throws Throwable { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + Completable.error(new TestException()) + .doOnLifecycle(onSubscribe, onDispose) + .test() + .assertFailure(TestException.class); + + verify(onSubscribe).accept(any()); + verify(onDispose, never()).run(); + } + + @Test + public void onSubscribeCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + doThrow(new TestException("First")).when(onSubscribe).accept(any()); + + Disposable bs = Disposable.empty(); + + new Completable() { + @Override + protected void subscribeActual(CompletableObserver observer) { + observer.onSubscribe(bs); + observer.onError(new TestException("Second")); + observer.onComplete(); + } + } + .doOnLifecycle(onSubscribe, onDispose) + .to(TestHelper.testConsumer()) + .assertFailureAndMessage(TestException.class, "First"); + + assertTrue(bs.isDisposed()); + + TestHelper.assertUndeliverable(errors, 0, TestException.class, "Second"); + + verify(onSubscribe).accept(any()); + verify(onDispose, never()).run(); + }); + } + + @Test + public void onDisposeCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + doThrow(new TestException("First")).when(onDispose).run(); + + CompletableSubject cs = CompletableSubject.create(); + + TestObserver to = cs + .doOnLifecycle(onSubscribe, onDispose) + .test(); + + assertTrue(cs.hasObservers()); + + to.dispose(); + + assertFalse(cs.hasObservers()); + + TestHelper.assertUndeliverable(errors, 0, TestException.class, "First"); + + verify(onSubscribe).accept(any()); + verify(onDispose).run(); + }); + } + + @Test + public void dispose() throws Throwable { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + CompletableSubject cs = CompletableSubject.create(); + + TestObserver to = cs + .doOnLifecycle(onSubscribe, onDispose) + .test(); + + assertTrue(cs.hasObservers()); + + to.dispose(); + + assertFalse(cs.hasObservers()); + + verify(onSubscribe).accept(any()); + verify(onDispose).run(); + } + + @Test + public void isDisposed() { + TestHelper.checkDisposed(CompletableSubject.create().doOnLifecycle(d -> { }, () -> { })); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeCompletable(m -> m.doOnLifecycle(d -> { }, () -> { })); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoOnTest.java index c2bf4948379..6f9698afbf3 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableDoOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromActionTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromActionTest.java index fb45fc3bad4..e697a91d349 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromActionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromActionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,6 +14,7 @@ package io.reactivex.rxjava3.internal.operators.completable; import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.*; import java.util.concurrent.atomic.AtomicInteger; @@ -22,13 +23,10 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Action; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.testsupport.TestHelper; public class CompletableFromActionTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromActionNull() { - Completable.fromAction(null); - } - @Test public void fromAction() { final AtomicInteger atomicInteger = new AtomicInteger(); @@ -113,7 +111,7 @@ public void run() throws Exception { .test(true) .assertEmpty(); - assertEquals(1, calls.get()); + assertEquals(0, calls.get()); } @Test @@ -129,6 +127,44 @@ public void run() throws Exception { .test(true) .assertEmpty(); - assertEquals(1, calls.get()); + assertEquals(0, calls.get()); + } + + @Test + public void disposedUpfront() throws Throwable { + Action run = mock(Action.class); + + Completable.fromAction(run) + .test(true) + .assertEmpty(); + + verify(run, never()).run(); + } + + @Test + public void disposeWhileRunningComplete() { + TestObserver to = new TestObserver<>(); + + Completable.fromAction(() -> { + to.dispose(); + }) + .subscribeWith(to) + .assertEmpty(); + } + + @Test + public void disposeWhileRunningError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + TestObserver to = new TestObserver<>(); + + Completable.fromAction(() -> { + to.dispose(); + throw new TestException(); + }) + .subscribeWith(to) + .assertEmpty(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromCallableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromCallableTest.java index 6cf88ce6675..940444f7a98 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromCallableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromCallableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -29,13 +29,9 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.schedulers.Schedulers; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class CompletableFromCallableTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromCallableNull() { - Completable.fromCallable(null); - } @Test public void fromCallable() { @@ -166,6 +162,7 @@ public String answer(InvocationOnMock invocation) throws Throwable { } @Test + @SuppressUndeliverable public void fromActionErrorsDisposed() { final AtomicInteger calls = new AtomicInteger(); Completable.fromCallable(new Callable() { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromMaybeTest.java index 9158d449c3f..db201e07a73 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromMaybeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromMaybeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,11 +18,6 @@ import io.reactivex.rxjava3.core.*; public class CompletableFromMaybeTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromMaybeNull() { - Completable.fromMaybe(null); - } - @Test public void fromMaybe() { Completable.fromMaybe(Maybe.just(1)) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromObservableTest.java index 9869ed04db4..5fc8ba08c64 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,11 +18,6 @@ import io.reactivex.rxjava3.core.*; public class CompletableFromObservableTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromObservableNull() { - Completable.fromObservable(null); - } - @Test public void fromObservable() { Completable.fromObservable(Observable.just(1)) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromPublisherTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromPublisherTest.java index 7cfd8992620..177dc4e156b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromPublisherTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromPublisherTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,11 +20,6 @@ import io.reactivex.rxjava3.testsupport.TestHelper; public class CompletableFromPublisherTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromPublisherNull() { - Completable.fromPublisher(null); - } - @Test public void fromPublisher() { Completable.fromPublisher(Flowable.just(1)) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromRunnableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromRunnableTest.java index 276ae320b62..2b3e9a65142 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromRunnableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromRunnableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,6 +14,7 @@ package io.reactivex.rxjava3.internal.operators.completable; import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.*; import java.util.concurrent.atomic.AtomicInteger; @@ -21,13 +22,10 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.testsupport.TestHelper; public class CompletableFromRunnableTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromRunnableNull() { - Completable.fromRunnable(null); - } - @Test public void fromRunnable() { final AtomicInteger atomicInteger = new AtomicInteger(); @@ -112,7 +110,7 @@ public void run() { .test(true) .assertEmpty(); - assertEquals(1, calls.get()); + assertEquals(0, calls.get()); } @Test @@ -128,6 +126,44 @@ public void run() { .test(true) .assertEmpty(); - assertEquals(1, calls.get()); + assertEquals(0, calls.get()); + } + + @Test + public void disposedUpfront() throws Throwable { + Runnable run = mock(Runnable.class); + + Completable.fromRunnable(run) + .test(true) + .assertEmpty(); + + verify(run, never()).run(); + } + + @Test + public void disposeWhileRunningComplete() { + TestObserver to = new TestObserver<>(); + + Completable.fromRunnable(() -> { + to.dispose(); + }) + .subscribeWith(to) + .assertEmpty(); + } + + @Test + public void disposeWhileRunningError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + TestObserver to = new TestObserver<>(); + + Completable.fromRunnable(() -> { + to.dispose(); + throw new TestException(); + }) + .subscribeWith(to) + .assertEmpty(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSingleTest.java index f9c6e82676e..14e5a29ac9e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,11 +18,6 @@ import io.reactivex.rxjava3.core.*; public class CompletableFromSingleTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromSingleNull() { - Completable.fromSingle(null); - } - @Test public void fromSingle() { Completable.fromSingle(Single.just(1)) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSupplierTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSupplierTest.java index 73dda447c82..453fc4c2c0c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSupplierTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableFromSupplierTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,15 +30,10 @@ import io.reactivex.rxjava3.functions.Supplier; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.schedulers.Schedulers; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class CompletableFromSupplierTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromSupplierNull() { - Completable.fromSupplier(null); - } - @Test public void fromSupplier() { final AtomicInteger atomicInteger = new AtomicInteger(); @@ -168,6 +163,7 @@ public String answer(InvocationOnMock invocation) throws Throwable { } @Test + @SuppressUndeliverable public void fromActionErrorsDisposed() { final AtomicInteger calls = new AtomicInteger(); Completable.fromSupplier(new Supplier() { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableHideTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableHideTest.java index 59352d76a5a..16afcaa075a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableHideTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableHideTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableLiftTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableLiftTest.java index 4f0ba23ce86..21cf3fb3050 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableLiftTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableLiftTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMaterializeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMaterializeTest.java index aa77e6a9758..8c301f50fa4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMaterializeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMaterializeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeIterableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeIterableTest.java index bacfc8521a2..cf3dc03c698 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeIterableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeIterableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,11 +14,14 @@ package io.reactivex.rxjava3.internal.operators.completable; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.CompositeDisposable; import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.internal.operators.completable.CompletableMergeIterable.MergeCompletableObserver; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.subjects.PublishSubject; @@ -124,4 +127,9 @@ public void remove() { to.assertEmpty(); } + + @Test + public void dispose() { + TestHelper.checkDisposed(new MergeCompletableObserver(new TestObserver(), new CompositeDisposable(), new AtomicInteger())); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeTest.java index 3482a53409d..38166ea6598 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableMergeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,6 +16,7 @@ import static org.junit.Assert.*; import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; import org.reactivestreams.Subscriber; @@ -25,9 +26,11 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.internal.util.AtomicThrowable; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.subjects.CompletableSubject; import io.reactivex.rxjava3.testsupport.*; public class CompletableMergeTest extends RxJavaTest { @@ -593,4 +596,33 @@ public Completable apply(Flowable upstream) { } }); } + + @Test + public void iterableCompleteLater() { + CompletableSubject cs = CompletableSubject.create(); + + TestObserver to = Completable.mergeDelayError(Arrays.asList(cs, cs, cs)) + .test(); + + to.assertEmpty(); + + cs.onComplete(); + + to.assertResult(); + } + + @Test + public void terminalDisposed() { + TestHelper.checkDisposed(new CompletableMergeArrayDelayError.TryTerminateAndReportDisposable(new AtomicThrowable())); + } + + @Test + public void innerDisposed() { + TestHelper.checkDisposed(new CompletableMergeArray.InnerCompletableObserver(new TestObserver(), new AtomicBoolean(), new CompositeDisposable(), 1)); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowableToCompletable(f -> Completable.merge(f)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableObserveOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableObserveOnTest.java index 6d5cc210640..f4613f5c597 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableObserveOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableObserveOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableOnErrorXTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableOnErrorXTest.java index 4a1333b5309..d7b1cae653f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableOnErrorXTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableOnErrorXTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,10 +15,16 @@ import static org.junit.Assert.assertEquals; +import java.io.IOException; + import org.junit.Test; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.subjects.CompletableSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; public class CompletableOnErrorXTest extends RxJavaTest { @@ -46,4 +52,55 @@ public CompletableSource apply(Throwable e) throws Exception { assertEquals(0, call[0]); } + + @Test + public void onErrorReturnConst() { + Completable.error(new TestException()) + .onErrorReturnItem(1) + .test() + .assertResult(1); + } + + @Test + public void onErrorReturn() { + Completable.error(new TestException()) + .onErrorReturn(Functions.justFunction(1)) + .test() + .assertResult(1); + } + + @Test + public void onErrorReturnFunctionThrows() { + TestHelper.assertCompositeExceptions(Completable.error(new TestException()) + .onErrorReturn(new Function() { + @Override + public Object apply(Throwable v) throws Exception { + throw new IOException(); + } + }) + .to(TestHelper.testConsumer()), TestException.class, IOException.class); + } + + @Test + public void onErrorReturnEmpty() { + Completable.complete() + .onErrorReturnItem(2) + .test() + .assertResult(); + } + + @Test + public void onErrorReturnDispose() { + TestHelper.checkDisposed(CompletableSubject.create().onErrorReturnItem(1)); + } + + @Test + public void onErrorReturnDoubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeCompletableToMaybe(new Function>() { + @Override + public MaybeSource apply(Completable v) throws Exception { + return v.onErrorReturnItem(1); + } + }); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletablePeekTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletablePeekTest.java index ddc5a16056e..827599e353e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletablePeekTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletablePeekTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableRepeatWhenTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableRepeatWhenTest.java index 6a80eda644b..d9a262b317e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableRepeatWhenTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableRepeatWhenTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableResumeNextTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableResumeNextTest.java index 5670264378f..a8f0390c632 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableResumeNextTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableResumeNextTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,18 +13,19 @@ package io.reactivex.rxjava3.internal.operators.completable; +import static org.mockito.Mockito.*; import org.junit.Test; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; -import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.testsupport.TestHelper; public class CompletableResumeNextTest extends RxJavaTest { @Test - public void resumeWithError() { + public void resumeNextError() { Completable.error(new TestException()) .onErrorResumeNext(Functions.justFunction(Completable.error(new TestException("second")))) .to(TestHelper.testConsumer()) @@ -58,4 +59,28 @@ public void disposed() { .onErrorResumeNext(Functions.justFunction(Completable.never())) ); } + + @Test + public void resumeWithNoError() throws Throwable { + Action action = mock(Action.class); + + Completable.complete() + .onErrorResumeWith(Completable.fromAction(action)) + .test() + .assertResult(); + + verify(action, never()).run(); + } + + @Test + public void resumeWithError() throws Throwable { + Action action = mock(Action.class); + + Completable.error(new TestException()) + .onErrorResumeWith(Completable.fromAction(action)) + .test() + .assertResult(); + + verify(action).run(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSafeSubscribeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSafeSubscribeTest.java new file mode 100644 index 00000000000..40c618ac0ab --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSafeSubscribeTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.completable; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import java.io.IOException; + +import org.junit.Test; +import org.mockito.InOrder; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class CompletableSafeSubscribeTest { + + @Test + public void normalError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + CompletableObserver consumer = mock(CompletableObserver.class); + + Completable.error(new TestException()) + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onError(any(TestException.class)); + order.verifyNoMoreInteractions(); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void normalEmpty() throws Throwable { + TestHelper.withErrorTracking(errors -> { + CompletableObserver consumer = mock(CompletableObserver.class); + + Completable.complete() + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onComplete(); + order.verifyNoMoreInteractions(); + }); + } + + @Test + public void onSubscribeCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + CompletableObserver consumer = mock(CompletableObserver.class); + doThrow(new TestException()).when(consumer).onSubscribe(any()); + + Disposable d = Disposable.empty(); + + new Completable() { + @Override + protected void subscribeActual(@NonNull CompletableObserver observer) { + observer.onSubscribe(d); + // none of the following should arrive at the consumer + observer.onError(new IOException()); + observer.onComplete(); + } + } + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verifyNoMoreInteractions(); + + assertTrue(d.isDisposed()); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + TestHelper.assertUndeliverable(errors, 1, IOException.class); + }); + } + + @Test + public void onErrorCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + CompletableObserver consumer = mock(CompletableObserver.class); + doThrow(new TestException()).when(consumer).onError(any()); + + new Completable() { + @Override + protected void subscribeActual(@NonNull CompletableObserver observer) { + observer.onSubscribe(Disposable.empty()); + // none of the following should arrive at the consumer + observer.onError(new IOException()); + } + } + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onError(any(IOException.class)); + order.verifyNoMoreInteractions(); + + TestHelper.assertError(errors, 0, CompositeException.class); + + CompositeException compositeException = (CompositeException)errors.get(0); + TestHelper.assertError(compositeException.getExceptions(), 0, IOException.class); + TestHelper.assertError(compositeException.getExceptions(), 1, TestException.class); + }); + } + + @Test + public void onCompleteCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + CompletableObserver consumer = mock(CompletableObserver.class); + doThrow(new TestException()).when(consumer).onComplete(); + + new Completable() { + @Override + protected void subscribeActual(@NonNull CompletableObserver observer) { + observer.onSubscribe(Disposable.empty()); + // none of the following should arrive at the consumer + observer.onComplete(); + } + } + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onComplete(); + order.verifyNoMoreInteractions(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSequenceEqualTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSequenceEqualTest.java new file mode 100644 index 00000000000..9e3fd56b99c --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSequenceEqualTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.completable; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Completable; +import io.reactivex.rxjava3.exceptions.TestException; + +public class CompletableSequenceEqualTest { + + @Test + public void bothComplete() { + Completable.sequenceEqual(Completable.complete(), Completable.complete()) + .test() + .assertResult(true); + } + + @Test + public void firstFails() { + Completable.sequenceEqual(Completable.error(new TestException()), Completable.complete()) + .test() + .assertFailure(TestException.class); + } + + @Test + public void secondFails() { + Completable.sequenceEqual(Completable.complete(), Completable.error(new TestException())) + .test() + .assertFailure(TestException.class); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableStartWithTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableStartWithTest.java new file mode 100644 index 00000000000..4b2ed6d588d --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableStartWithTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.completable; + +import static org.mockito.Mockito.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; + +public class CompletableStartWithTest { + + @Test + public void singleNormal() { + Completable.complete().startWith(Single.just(1)) + .test() + .assertResult(1); + } + + @Test + public void singleError() { + Runnable run = mock(Runnable.class); + + Completable.fromRunnable(run).startWith(Single.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } + + @Test + public void maybeNormal() { + Completable.complete().startWith(Maybe.just(1)) + .test() + .assertResult(1); + } + + @Test + public void maybeEmptyNormal() { + Completable.complete().startWith(Maybe.empty()) + .test() + .assertResult(); + } + + @Test + public void maybeError() { + Runnable run = mock(Runnable.class); + + Completable.fromRunnable(run).startWith(Maybe.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSubscribeOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSubscribeOnTest.java index 22d826fc702..3c20a125881 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSubscribeOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSubscribeOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSubscribeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSubscribeTest.java index 7c140db31d3..f0fded59963 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSubscribeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSubscribeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSwitchOnNextTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSwitchOnNextTest.java new file mode 100644 index 00000000000..312f9653ed3 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableSwitchOnNextTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.completable; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.subjects.CompletableSubject; + +public class CompletableSwitchOnNextTest extends RxJavaTest { + + @Test + public void normal() { + Runnable run = mock(Runnable.class); + + Completable.switchOnNext( + Flowable.range(1, 10) + .map(v -> { + if (v % 2 == 0) { + return Completable.fromRunnable(run); + } + return Completable.complete(); + }) + ) + .test() + .assertResult(); + + verify(run, times(5)).run(); + } + + @Test + public void normalDelayError() { + Runnable run = mock(Runnable.class); + + Completable.switchOnNextDelayError( + Flowable.range(1, 10) + .map(v -> { + if (v % 2 == 0) { + return Completable.fromRunnable(run); + } + return Completable.complete(); + }) + ) + .test() + .assertResult(); + + verify(run, times(5)).run(); + } + + @Test + public void noDelaySwitch() { + PublishProcessor pp = PublishProcessor.create(); + + TestObserver to = Completable.switchOnNext(pp).test(); + + assertTrue(pp.hasSubscribers()); + + to.assertEmpty(); + + CompletableSubject cs1 = CompletableSubject.create(); + CompletableSubject cs2 = CompletableSubject.create(); + + pp.onNext(cs1); + + assertTrue(cs1.hasObservers()); + + pp.onNext(cs2); + + assertFalse(cs1.hasObservers()); + assertTrue(cs2.hasObservers()); + + pp.onComplete(); + + assertTrue(cs2.hasObservers()); + + cs2.onComplete(); + + to.assertResult(); + } + + @Test + public void delaySwitch() { + PublishProcessor pp = PublishProcessor.create(); + + TestObserver to = Completable.switchOnNextDelayError(pp).test(); + + assertTrue(pp.hasSubscribers()); + + to.assertEmpty(); + + CompletableSubject cs1 = CompletableSubject.create(); + CompletableSubject cs2 = CompletableSubject.create(); + + pp.onNext(cs1); + + assertTrue(cs1.hasObservers()); + + pp.onNext(cs2); + + assertFalse(cs1.hasObservers()); + assertTrue(cs2.hasObservers()); + + assertTrue(cs2.hasObservers()); + + cs2.onError(new TestException()); + + assertTrue(pp.hasSubscribers()); + + to.assertEmpty(); + + pp.onComplete(); + + to.assertFailure(TestException.class); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTakeUntilTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTakeUntilTest.java index 3458ef97722..1eefff19565 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTakeUntilTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTakeUntilTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimeoutTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimeoutTest.java index a2f0771ab4c..86f2f2890a5 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimeoutTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimeoutTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimerTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimerTest.java index 7f6b3399616..bfd87a1af66 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimerTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableTimerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -37,7 +37,7 @@ public void dispose() { public void timerInterruptible() throws Exception { ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); try { - for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec) }) { + for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec, true) }) { final AtomicBoolean interrupted = new AtomicBoolean(); TestObserver to = Completable.timer(1, TimeUnit.MILLISECONDS, s) .doOnComplete(new Action() { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToFlowableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToFlowableTest.java index d1fdb548fa4..8c10ea5225a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToFlowableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToFlowableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToFutureTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToFutureTest.java new file mode 100644 index 00000000000..c857e95ebb8 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToFutureTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.completable; + +import static org.junit.Assert.*; + +import java.util.concurrent.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.subjects.CompletableSubject; + +public class CompletableToFutureTest extends RxJavaTest { + + @Test + public void empty() throws Exception { + assertNull(Completable.complete() + .subscribeOn(Schedulers.computation()) + .toFuture() + .get()); + } + + @Test + public void error() throws InterruptedException { + try { + Completable.error(new TestException()) + .subscribeOn(Schedulers.computation()) + .toFuture() + .get(); + + fail("Should have thrown!"); + } catch (ExecutionException ex) { + assertTrue("" + ex.getCause(), ex.getCause() instanceof TestException); + } + } + + @Test + public void cancel() { + CompletableSubject cs = CompletableSubject.create(); + + Future f = cs.toFuture(); + + assertTrue(cs.hasObservers()); + + f.cancel(true); + + assertFalse(cs.hasObservers()); + } + + @Test + public void cancel2() { + CompletableSubject cs = CompletableSubject.create(); + + Future f = cs.toFuture(); + + assertTrue(cs.hasObservers()); + + f.cancel(false); + + assertFalse(cs.hasObservers()); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToObservableTest.java index f1bbda0353f..7ad93e9bef6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableToObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,16 +13,10 @@ package io.reactivex.rxjava3.internal.operators.completable; -import static org.junit.Assert.*; - import org.junit.Test; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; -import io.reactivex.rxjava3.internal.operators.completable.CompletableToObservable.ObserverCompletableObserver; -import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.testsupport.TestHelper; public class CompletableToObservableTest extends RxJavaTest { @@ -37,36 +31,4 @@ public Observable apply(Completable c) throws Exception { }); } - @Test - public void fusion() throws Exception { - TestObserver to = new TestObserver<>(); - - ObserverCompletableObserver co = new ObserverCompletableObserver(to); - - Disposable d = Disposable.empty(); - - co.onSubscribe(d); - - assertEquals(QueueFuseable.NONE, co.requestFusion(QueueFuseable.SYNC)); - - assertEquals(QueueFuseable.ASYNC, co.requestFusion(QueueFuseable.ASYNC)); - - assertEquals(QueueFuseable.ASYNC, co.requestFusion(QueueFuseable.ANY)); - - assertTrue(co.isEmpty()); - - assertNull(co.poll()); - - co.clear(); - - assertFalse(co.isDisposed()); - - co.dispose(); - - assertTrue(d.isDisposed()); - - assertTrue(co.isDisposed()); - - TestHelper.assertNoOffer(co); - } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableUnsafeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableUnsafeTest.java index 4581a8944d0..72b28edea03 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableUnsafeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableUnsafeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableUsingTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableUsingTest.java index 6a7ddd564bd..72e4d164917 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableUsingTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/completable/CompletableUsingTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/AbstractFlowableWithUpstreamTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/AbstractFlowableWithUpstreamTest.java index e109a0a5448..65f593211cd 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/AbstractFlowableWithUpstreamTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/AbstractFlowableWithUpstreamTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableLatestTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableLatestTest.java index 825c74e3219..a842c39c2be 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableLatestTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableLatestTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableMostRecentTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableMostRecentTest.java index f652e9fbf63..92513b30724 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableMostRecentTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableMostRecentTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,10 +26,6 @@ import io.reactivex.rxjava3.schedulers.TestScheduler; public class BlockingFlowableMostRecentTest extends RxJavaTest { - @Test - public void mostRecentNull() { - assertNull(Flowable.never().blockingMostRecent(null).iterator().next()); - } @Test public void mostRecent() { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableNextTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableNextTest.java index 35c1501ae09..718a7ba6a16 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableNextTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableNextTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -223,8 +223,8 @@ public void nextWithCallingHasNextMultipleTimes() { /** * Confirm that no buffering or blocking of the Observable onNext calls occurs and it just grabs the next emitted value. - *

- * This results in output such as => a: 1 b: 2 c: 89 + *

+ * This results in output such as {@code => a: 1 b: 2 c: 89} * * @throws Throwable some method call is declared throws */ diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableToFutureTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableToFutureTest.java index cf8ad48a5fd..6da74eea030 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableToFutureTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableToFutureTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import static org.junit.Assert.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableToIteratorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableToIteratorTest.java index 64b22b17859..e5ad7806d36 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableToIteratorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BlockingFlowableToIteratorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -152,7 +152,7 @@ public void emptyThrowsNoSuch() { it.next(); } - @Test(expected = MissingBackpressureException.class) + @Test(expected = QueueOverflowException.class) public void overflowQueue() { Iterator it = new Flowable() { @Override diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BufferUntilSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BufferUntilSubscriberTest.java index 69abd706ebe..6cdc17d210a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BufferUntilSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/BufferUntilSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAllTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAllTest.java index 387a2017dd6..2b66a48bd0d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAllTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAllTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAmbTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAmbTest.java index 0657a154741..1a1ceca9266 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAmbTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAmbTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -25,6 +25,7 @@ import org.mockito.InOrder; import org.reactivestreams.*; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.CompositeDisposable; import io.reactivex.rxjava3.exceptions.TestException; @@ -401,7 +402,8 @@ public void disposed() { @Test public void manySources() { - Flowable[] a = new Flowable[32]; + @SuppressWarnings("unchecked") + Flowable[] a = new Flowable[32]; Arrays.fill(a, Flowable.never()); a[31] = Flowable.just(1); @@ -660,4 +662,34 @@ public void subscribe(Subscriber subscriber) { .test() .assertResult(1); } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.amb(Arrays.asList(Flowable.never(), Flowable.never()))); + } + + @Test + public void requestAfterCancel() { + Flowable.amb(Arrays.asList(Flowable.never(), Flowable.never())) + .subscribe(new FlowableSubscriber() { + + @Override + public void onNext(@NonNull Object t) { + } + + @Override + public void onError(Throwable t) { + } + + @Override + public void onComplete() { + } + + @Override + public void onSubscribe(@NonNull Subscription s) { + s.cancel(); + s.request(1); + } + }); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAnyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAnyTest.java index e121cbc9249..2f18a90c64e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAnyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAnyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAsObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAsObservableTest.java index 15cd39ea0aa..d922ef48c34 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAsObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAsObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAutoConnectTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAutoConnectTest.java index d2213dd9111..07d1e66214e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAutoConnectTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableAutoConnectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBlockingTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBlockingTest.java index db560e03278..a1facf40460 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBlockingTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBlockingTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferTest.java index 87a0eeaf385..c1b08990bb7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableBufferTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -34,7 +34,7 @@ import io.reactivex.rxjava3.internal.operators.flowable.FlowableBufferTimed.*; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.*; import io.reactivex.rxjava3.subscribers.*; import io.reactivex.rxjava3.testsupport.TestHelper; @@ -2388,4 +2388,112 @@ public List get() throws Exception { .assertFailure(TestException.class) ; } + + @Test + public void exactBadRequest() { + TestHelper.assertBadRequestReported(Flowable.never().buffer(1)); + } + + @Test + public void skipBadRequest() { + TestHelper.assertBadRequestReported(Flowable.never().buffer(1, 2)); + } + + @Test + public void overlapBadRequest() { + TestHelper.assertBadRequestReported(Flowable.never().buffer(2, 1)); + } + + @Test + public void bufferExactBoundedOnNextAfterDispose() { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.unsafeCreate(s -> { + s.onSubscribe(new BooleanSubscription()); + ts.cancel(); + s.onNext(1); + }) + .buffer(1, TimeUnit.MINUTES, 2) + .subscribe(ts); + + ts.assertEmpty(); + } + + @Test + public void boundaryCloseCompleteRace() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + BehaviorProcessor bp = BehaviorProcessor.createDefault(1); + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber> ts = bp + .buffer(BehaviorProcessor.createDefault(0), v -> pp) + .test(); + + TestHelper.race( + () -> bp.onComplete(), + () -> pp.onComplete() + ); + + ts.assertResult(Arrays.asList(1)); + } + } + + @Test + public void doubleOnSubscribeStartEnd() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.buffer(Flowable.never(), v -> Flowable.never())); + } + + @Test + public void cancel() { + TestHelper.checkDisposed(Flowable.never().buffer(Flowable.never(), v -> Flowable.never())); + } + + @Test + public void startEndCancelAfterOneBuffer() { + BehaviorProcessor.createDefault(1) + .buffer(BehaviorProcessor.createDefault(2), v -> Flowable.just(1)) + .takeUntil(v -> true) + .test() + .assertResult(Arrays.asList()); + } + + @Test + public void startEndCompleteOnBoundary() { + Flowable.empty() + .buffer(Flowable.never(), v -> Flowable.just(1)) + .take(1) + .test() + .assertResult(); + } + + @Test + public void startEndBackpressure() { + BehaviorProcessor.createDefault(1) + .buffer(BehaviorProcessor.createDefault(2), v -> Flowable.just(1)) + .test(1L) + .assertValuesOnly(Arrays.asList()); + } + + @Test + public void startEndBackpressureMoreWork() { + PublishProcessor bp = PublishProcessor.create(); + PublishProcessor pp = PublishProcessor.create(); + AtomicInteger counter = new AtomicInteger(); + + TestSubscriber> ts = bp + .buffer(pp, v -> Flowable.just(1)) + .doOnNext(v -> { + if (counter.getAndIncrement() == 0) { + pp.onNext(2); + pp.onComplete(); + } + }) + .test(1L); + + pp.onNext(1); + bp.onNext(1); + + ts + .assertValuesOnly(Arrays.asList()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCacheTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCacheTest.java index a3170558897..e71315351d0 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCacheTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCacheTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -511,4 +511,18 @@ public void backpressure() { .requestMore(3) .assertResult(1, 2, 3, 4, 5); } + + @Test + public void addRemoveRace() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + Flowable f = Flowable.never().cache(); + + TestSubscriber ts = f.test(); + + TestHelper.race( + () -> ts.cancel(), + () -> f.test() + ); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCastTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCastTest.java index c39b1972f00..dc26fdccaa1 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCastTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCastTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCombineLatestTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCombineLatestTest.java index 6829c999862..0f07148179d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCombineLatestTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCombineLatestTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,8 +30,9 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.internal.operators.flowable.FlowableZipTest.ArgsToString; +import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.schedulers.*; @@ -1073,7 +1074,7 @@ public List apply(Object[] t) throws Exception { .test() .assertResult(expected); - Flowable.combineLatestDelayError(sources, new Function>() { + Flowable.combineLatestArrayDelayError(sources, new Function>() { @Override public List apply(Object[] t) throws Exception { return Arrays.asList(t); @@ -1104,7 +1105,7 @@ public Object apply(Object[] a) throws Exception { @SuppressWarnings("unchecked") public void combineLatestDelayErrorArrayOfSources() { - Flowable.combineLatestDelayError(new Flowable[] { + Flowable.combineLatestArrayDelayError(new Flowable[] { Flowable.just(1), Flowable.just(2) }, new Function() { @Override @@ -1120,7 +1121,7 @@ public Object apply(Object[] a) throws Exception { @SuppressWarnings("unchecked") public void combineLatestDelayErrorArrayOfSourcesWithError() { - Flowable.combineLatestDelayError(new Flowable[] { + Flowable.combineLatestArrayDelayError(new Flowable[] { Flowable.just(1), Flowable.just(2).concatWith(Flowable.error(new TestException())) }, new Function() { @Override @@ -1171,7 +1172,7 @@ public void combineLatestArrayEmpty() { @SuppressWarnings("unchecked") @Test public void combineLatestDelayErrorEmpty() { - assertSame(Flowable.empty(), Flowable.combineLatestDelayError(new Flowable[0], Functions.identity(), 16)); + assertSame(Flowable.empty(), Flowable.combineLatestArrayDelayError(new Flowable[0], Functions.identity(), 16)); } @Test @@ -1295,7 +1296,7 @@ public Object apply(Object a, Object b) throws Exception { @SuppressWarnings("unchecked") @Test public void errorDelayed() { - Flowable.combineLatestDelayError( + Flowable.combineLatestArrayDelayError( new Publisher[] { Flowable.error(new TestException()), Flowable.just(1) }, new Function() { @Override @@ -1312,7 +1313,7 @@ public Object apply(Object[] a) throws Exception { @SuppressWarnings("unchecked") @Test public void errorDelayed2() { - Flowable.combineLatestDelayError( + Flowable.combineLatestArrayDelayError( new Publisher[] { Flowable.error(new TestException()).startWithItem(1), Flowable.empty() }, new Function() { @Override @@ -1394,7 +1395,7 @@ public Object apply(Object[] a) throws Exception { public void combine2Flowable2Errors() throws Exception { List errors = TestHelper.trackPluginErrors(); try { - TestSubscriber testObserver = TestSubscriber.create(); + TestSubscriber testSubscriber = TestSubscriber.create(); TestScheduler testScheduler = new TestScheduler(); @@ -1459,11 +1460,11 @@ public void run() throws Exception { System.out.println("combineLatestDelayError: doFinally"); } }) - .subscribe(testObserver); + .subscribe(testSubscriber); testScheduler.advanceTimeBy(100, TimeUnit.MILLISECONDS); - testObserver.awaitDone(5, TimeUnit.SECONDS); + testSubscriber.awaitDone(5, TimeUnit.SECONDS); assertTrue(errors.toString(), errors.isEmpty()); } finally { @@ -1558,4 +1559,230 @@ public Integer apply(Object[] t) throws Throwable { .test() .assertResult(2); } + + @Test + public void FlowableSourcesInIterable() { + Flowable source = new Flowable() { + @Override + public void subscribeActual(Subscriber s) { + Flowable.just(1).subscribe(s); + } + }; + + Flowable.combineLatest(Arrays.asList(source, source), new Function() { + @Override + public Integer apply(Object[] t) throws Throwable { + return 2; + } + }) + .test() + .assertResult(2); + } + + @Test + public void onCompleteDisposeRace() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + + TestSubscriber ts = new TestSubscriber<>(); + PublishProcessor pp = PublishProcessor.create(); + + Flowable.combineLatest(pp, Flowable.never(), (a, b) -> a) + .subscribe(ts); + + TestHelper.race(() -> pp.onComplete(), () -> ts.cancel()); + } + } + + @Test + public void onErrorDisposeDelayErrorRace() throws Throwable { + TestHelper.withErrorTracking(errors -> { + TestException ex = new TestException(); + + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + + TestSubscriberEx ts = new TestSubscriberEx<>(); + AtomicReference> ref = new AtomicReference<>(); + Flowable f = new Flowable() { + @Override + public void subscribeActual(Subscriber s) { + ref.set(s); + } + }; + + Flowable.combineLatestDelayError(Arrays.asList(f, Flowable.never()), (a) -> a) + .subscribe(ts); + + ref.get().onSubscribe(new BooleanSubscription()); + + TestHelper.race(() -> ref.get().onError(ex), () -> ts.cancel()); + + if (ts.errors().isEmpty()) { + TestHelper.assertUndeliverable(errors, 0, TestException.class); + } + } + }); + } + + @Test + public void doneButNotEmpty() { + PublishProcessor pp1 = PublishProcessor.create(); + PublishProcessor pp2 = PublishProcessor.create(); + + TestSubscriber ts = Flowable.combineLatest(pp1, pp2, (a, b) -> a + b) + .doOnNext(v -> { + if (v == 2) { + pp2.onNext(3); + pp2.onComplete(); + pp1.onComplete(); + } + }) + .test(); + + pp1.onNext(1); + pp2.onNext(1); + + ts.assertResult(2, 4); + } + + @Test + public void iterableNullPublisher() { + Flowable.combineLatest(Arrays.asList(Flowable.never(), null), (a) -> a) + .test() + .assertFailure(NullPointerException.class); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.combineLatest(Flowable.never(), Flowable.never(), (a, b) -> a)); + } + + @Test + public void syncFusionRejected() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.SYNC); + + Flowable.combineLatest(Flowable.never(), Flowable.never(), (a, b) -> a) + .subscribe(ts); + + ts.assertFuseable() + .assertFusionMode(QueueFuseable.NONE); + } + + @Test + public void bounderyFusionRejected() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.ANY | QueueFuseable.BOUNDARY); + + Flowable.combineLatest(Flowable.never(), Flowable.never(), (a, b) -> a) + .subscribe(ts); + + ts.assertFuseable() + .assertFusionMode(QueueFuseable.NONE); + } + + @Test + public void fusedNormal() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.ANY); + + Flowable.combineLatest(Flowable.just(1), Flowable.just(2), (a, b) -> a + b) + .subscribeWith(ts) + .assertFuseable() + .assertFusionMode(QueueFuseable.ASYNC) + .assertResult(3); + } + + @Test + public void fusedToParallel() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.ANY); + + Flowable.combineLatest(Flowable.just(1), Flowable.just(2), (a, b) -> a + b) + .parallel() + .sequential() + .subscribeWith(ts) + .assertResult(3); + } + + @Test + public void fusedToParallel2() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.ANY); + + Flowable.combineLatest(Flowable.just(1), Flowable.just(2), (a, b) -> a + b) + .compose(TestHelper.flowableStripBoundary()) + .parallel() + .sequential() + .subscribeWith(ts) + .assertResult(3); + } + + @Test + public void fusedError() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.ANY); + + Flowable.combineLatest(Flowable.just(1), Flowable.error(new TestException()), (a, b) -> a + b) + .subscribeWith(ts) + .assertFuseable() + .assertFusionMode(QueueFuseable.ASYNC) + .assertFailure(TestException.class); + } + + @Test + public void nonFusedMoreWorkBeforeTermination() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = Flowable.combineLatest(pp, Flowable.just(1), (a, b) -> a + b) + .doOnNext(v -> { + if (v == 1) { + pp.onNext(2); + pp.onComplete(); + } + }) + .test(); + + pp.onNext(0); + + ts.assertResult(1, 3); + } + + @Test + public void nonFusedDelayErrorMoreWorkBeforeTermination() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber> ts = Flowable.combineLatestDelayError(Arrays.asList(pp, Flowable.just(1)), a -> Arrays.asList(a)) + .doOnNext(v -> { + if (((Integer)v.get(0)) == 0) { + pp.onNext(2); + pp.onComplete(); + } + }) + .test(); + + pp.onNext(0); + + ts.assertResult(Arrays.asList(0, 1), Arrays.asList(2, 1)); + } + + @Test + public void fusedCombinerCrashError() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.ANY); + + Flowable.combineLatest(Flowable.just(1), Flowable.just(1), (a, b) -> { throw new TestException(); }) + .subscribeWith(ts) + .assertFuseable() + .assertFusionMode(QueueFuseable.ASYNC) + .assertFailure(TestException.class); + } + + @Test + public void fusedCombinerCrashError2() { + Flowable.combineLatest(Flowable.just(1), Flowable.just(1), (a, b) -> { throw new TestException(); }) + .compose(TestHelper.flowableStripBoundary()) + .rebatchRequests(10) + .test() + .assertFailure(TestException.class); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatDelayErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatDelayErrorTest.java index 22e23a43914..39d6cf6ff59 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatDelayErrorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatDelayErrorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapEagerTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapEagerTest.java index 0adfd655b02..3711aecec41 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapEagerTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapEagerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -744,7 +744,7 @@ public void Flowable() { } @Test - public void ObservableCapacityHint() { + public void publisherCapacityHint() { Flowable source = Flowable.just(1); TestSubscriber ts = TestSubscriber.create(); @@ -1351,4 +1351,84 @@ public Flowable apply(Integer v) throws Throwable { } }); } + + @Test + public void iterableDelayError() { + Flowable.concatEagerDelayError(Arrays.asList( + Flowable.range(1, 2), + Flowable.error(new TestException()), + Flowable.range(3, 3) + )) + .test() + .assertFailure(TestException.class, 1, 2, 3, 4, 5); + } + + @Test + public void iterableDelayErrorMaxConcurrency() { + Flowable.concatEagerDelayError(Arrays.asList( + Flowable.range(1, 2), + Flowable.error(new TestException()), + Flowable.range(3, 3) + ), 1, 1) + .test() + .assertFailure(TestException.class, 1, 2, 3, 4, 5); + } + + @Test + public void publisherDelayError() { + Flowable.concatEagerDelayError(Flowable.fromArray( + Flowable.range(1, 2), + Flowable.error(new TestException()), + Flowable.range(3, 3) + )) + .test() + .assertFailure(TestException.class, 1, 2, 3, 4, 5); + } + + @Test + public void publisherDelayErrorMaxConcurrency() { + Flowable.concatEagerDelayError(Flowable.fromArray( + Flowable.range(1, 2), + Flowable.error(new TestException()), + Flowable.range(3, 3) + ), 1, 1) + .test() + .assertFailure(TestException.class, 1, 2, 3, 4, 5); + } + + @Test + public void innerSyncFused() { + Flowable.just(1) + .hide() + .concatMapEagerDelayError(v -> Flowable.range(1, 10), true, 1, 1) + .test() + .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().concatMapEagerDelayError(v -> Flowable.never(), false)); + } + + @Test + public void cancelAfterOnNext() { + Flowable.just(1) + .hide() + .concatMapEagerDelayError(v -> Flowable.range(1, 5).hide(), true) + .takeUntil(v -> true) + .test() + .assertResult(1); + } + + @Test + public void noInnerQueue() { + Flowable.just(1) + .hide() + .concatMapEagerDelayError(v -> Flowable.fromPublisher(s -> { }), true) + .test(0L) + .assertEmpty() + .requestMore(1L) + .assertEmpty() + ; + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapSchedulerTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapSchedulerTest.java index 0cd75621998..027157ce027 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapSchedulerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,17 +18,18 @@ import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.*; import org.junit.Test; import org.reactivestreams.*; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.internal.schedulers.ImmediateThinScheduler; -import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.Schedulers; @@ -65,6 +66,56 @@ public Publisher apply(String v) .assertResult("RxSingleScheduler"); } + @Test + public void innerScalarRequestRace() { + Flowable just = Flowable.just(1); + int n = 1000; + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + PublishProcessor> source = PublishProcessor.create(); + + TestSubscriber ts = source + .concatMap(v -> v, n + 1, ImmediateThinScheduler.INSTANCE) + .test(1L); + + TestHelper.race(() -> { + for (int j = 0; j < n; j++) { + source.onNext(just); + } + }, () -> { + for (int j = 0; j < n; j++) { + ts.request(1); + } + }); + + ts.assertValueCount(n); + } + } + + @Test + public void innerScalarRequestRaceDelayError() { + Flowable just = Flowable.just(1); + int n = 1000; + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + PublishProcessor> source = PublishProcessor.create(); + + TestSubscriber ts = source + .concatMapDelayError(v -> v, true, n + 1, ImmediateThinScheduler.INSTANCE) + .test(1L); + + TestHelper.race(() -> { + for (int j = 0; j < n; j++) { + source.onNext(just); + } + }, () -> { + for (int j = 0; j < n; j++) { + ts.request(1); + } + }); + + ts.assertValueCount(n); + } + } + @Test public void boundaryFusionDelayError() { Flowable.range(1, 10000) @@ -304,7 +355,7 @@ public Flowable apply(Integer t) throws Throwable { } @Test - public void issue2890NoStackoverflow() throws InterruptedException { + public void issue2890NoStackoverflow() throws InterruptedException, TimeoutException { final ExecutorService executor = Executors.newFixedThreadPool(2); final Scheduler sch = Schedulers.from(executor); @@ -349,7 +400,11 @@ public void onError(Throwable e) { } }); - executor.awaitTermination(20000, TimeUnit.MILLISECONDS); + long awaitTerminationTimeoutMillis = 100_000; + if (!executor.awaitTermination(awaitTerminationTimeoutMillis, TimeUnit.MILLISECONDS)) { + throw new TimeoutException("Completed " + counter.get() + "/" + n + " before timed out after " + + awaitTerminationTimeoutMillis + " milliseconds."); + } assertEquals(n, counter.get()); } @@ -569,7 +624,7 @@ protected void subscribeActual(Subscriber s) { } .concatMap(Functions.justFunction(Flowable.just(2)), 8, ImmediateThinScheduler.INSTANCE) .test(0L) - .assertFailure(IllegalStateException.class); + .assertFailure(QueueOverflowException.class); } @Test @@ -1088,4 +1143,141 @@ public Publisher apply(Integer v) throws Throwable { } }); } + + @Test + public void fusionRejected() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + + TestHelper.rejectFlowableFusion() + .concatMap(v -> Flowable.never(), 2, ImmediateThinScheduler.INSTANCE) + .subscribe(ts); + } + + @Test + public void fusionRejectedDelayErrorr() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + + TestHelper.rejectFlowableFusion() + .concatMapDelayError(v -> Flowable.never(), true, 2, ImmediateThinScheduler.INSTANCE) + .subscribe(ts); + } + + @Test + public void scalarInnerJustDispose() { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.just(1) + .hide() + .concatMap(v -> Flowable.fromCallable(() -> { + ts.cancel(); + return 1; + }), 2, ImmediateThinScheduler.INSTANCE) + .subscribe(ts); + + ts.assertEmpty(); + } + + @Test + public void scalarInnerJustDisposeDelayError() { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.just(1) + .hide() + .concatMapDelayError(v -> Flowable.fromCallable(() -> { + ts.cancel(); + return 1; + }), true, 2, ImmediateThinScheduler.INSTANCE) + .subscribe(ts); + + ts.assertEmpty(); + } + + static final class EmptyDisposingFlowable extends Flowable + implements Supplier { + final TestSubscriber ts; + EmptyDisposingFlowable(TestSubscriber ts) { + this.ts = ts; + } + + @Override + protected void subscribeActual(@NonNull Subscriber subscriber) { + EmptySubscription.complete(subscriber); + } + + @Override + public @NonNull Object get() throws Throwable { + ts.cancel(); + return null; + } + } + + @Test + public void scalarInnerEmptyDisposeDelayError() { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.just(1) + .hide() + .concatMapDelayError(v -> new EmptyDisposingFlowable(ts), + true, 2, ImmediateThinScheduler.INSTANCE + ) + .subscribe(ts); + + ts.assertEmpty(); + } + + @Test + public void mainErrorInnerNextIgnoreCancel() { + AtomicReference> ref = new AtomicReference<>(); + + Flowable.just(1).concatWith(Flowable.error(new TestException())) + .concatMap(v -> Flowable.fromPublisher(ref::set), 2, ImmediateThinScheduler.INSTANCE) + .doOnError(e -> { + ref.get().onSubscribe(new BooleanSubscription()); + ref.get().onNext(1); + }) + .test() + .assertFailure(TestException.class); + } + + @Test + public void scalarSupplierMainError() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = pp.concatMap(v -> Flowable.fromCallable(() -> { + pp.onError(new TestException()); + return 2; + }), 2, ImmediateThinScheduler.INSTANCE) + .test() + ; + + pp.onNext(1); + + ts.assertFailure(TestException.class); + } + + @Test + public void mainErrorInnerErrorRace() throws Throwable { + TestHelper.withErrorTracking(errors -> { + TestException ex1 = new TestException(); + TestException ex2 = new TestException(); + + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + AtomicReference> ref1 = new AtomicReference<>(); + AtomicReference> ref2 = new AtomicReference<>(); + + TestSubscriber ts = Flowable.fromPublisher(ref1::set) + .concatMap(v -> Flowable.fromPublisher(ref2::set), 2, ImmediateThinScheduler.INSTANCE) + .test(); + + ref1.get().onSubscribe(new BooleanSubscription()); + ref1.get().onNext(1); + ref2.get().onSubscribe(new BooleanSubscription()); + + TestHelper.race(() -> ref1.get().onError(ex1), () -> ref2.get().onError(ex2)); + + ts.assertError(RuntimeException.class); + errors.clear(); + } + }); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapTest.java index e815c3675e0..10df043ba54 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,7 +24,8 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.operators.flowable.FlowableConcatMap.WeakScalarSubscription; +import io.reactivex.rxjava3.internal.operators.flowable.FlowableConcatMap.SimpleScalarSubscription; +import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.TestHelper; @@ -32,9 +33,9 @@ public class FlowableConcatMapTest extends RxJavaTest { @Test - public void weakSubscriptionRequest() { + public void simpleSubscriptionRequest() { TestSubscriber ts = new TestSubscriber<>(0); - WeakScalarSubscription ws = new WeakScalarSubscription<>(1, ts); + SimpleScalarSubscription ws = new SimpleScalarSubscription<>(1, ts); ts.onSubscribe(ws); ws.request(0); @@ -78,6 +79,56 @@ public Publisher apply(String v) .assertResult("RxSingleScheduler"); } + @Test + public void innerScalarRequestRace() { + Flowable just = Flowable.just(1); + int n = 1000; + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + PublishProcessor> source = PublishProcessor.create(); + + TestSubscriber ts = source + .concatMap(v -> v, n + 1) + .test(1L); + + TestHelper.race(() -> { + for (int j = 0; j < n; j++) { + source.onNext(just); + } + }, () -> { + for (int j = 0; j < n; j++) { + ts.request(1); + } + }); + + ts.assertValueCount(n); + } + } + + @Test + public void innerScalarRequestRaceDelayError() { + Flowable just = Flowable.just(1); + int n = 1000; + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + PublishProcessor> source = PublishProcessor.create(); + + TestSubscriber ts = source + .concatMapDelayError(v -> v, true, n + 1) + .test(1L); + + TestHelper.race(() -> { + for (int j = 0; j < n; j++) { + source.onNext(just); + } + }, () -> { + for (int j = 0; j < n; j++) { + ts.request(1); + } + }); + + ts.assertValueCount(n); + } + } + @Test public void boundaryFusionDelayError() { Flowable.range(1, 10000) @@ -252,4 +303,23 @@ public Publisher apply(Integer v) throws Throwable { } }); } + + @Test + public void asyncFusedSource() { + UnicastProcessor up = UnicastProcessor.create(); + up.onNext(1); + up.onComplete(); + + up.concatMap(v -> Flowable.just(1).hide()) + .test() + .assertResult(1); + } + + @Test + public void scalarCallableSource() { + Flowable.fromCallable(() -> 1) + .concatMap(v -> Flowable.just(1)) + .test() + .assertResult(1); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatTest.java index 208f7b1b513..5a0634ffb66 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,6 +17,7 @@ import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.io.IOException; import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.*; @@ -27,7 +28,7 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; @@ -728,7 +729,7 @@ public void subscribe(Subscriber s) { } @Test - public void issue2890NoStackoverflow() throws InterruptedException { + public void issue2890NoStackoverflow() throws InterruptedException, TimeoutException { final ExecutorService executor = Executors.newFixedThreadPool(2); final Scheduler sch = Schedulers.from(executor); @@ -773,7 +774,11 @@ public void onError(Throwable e) { } }); - executor.awaitTermination(20000, TimeUnit.MILLISECONDS); + long awaitTerminationTimeoutMillis = 100_000; + if (!executor.awaitTermination(awaitTerminationTimeoutMillis, TimeUnit.MILLISECONDS)) { + throw new TimeoutException("Completed " + counter.get() + "/" + n + " before timed out after " + + awaitTerminationTimeoutMillis + " milliseconds."); + } assertEquals(n, counter.get()); } @@ -1286,7 +1291,7 @@ protected void subscribeActual(Subscriber s) { } .concatMap(Functions.justFunction(Flowable.just(2)), 8) .test(0L) - .assertFailure(IllegalStateException.class); + .assertFailure(QueueOverflowException.class); } @Test @@ -1644,4 +1649,28 @@ public void run() throws Exception { assertEquals(0, counter.get()); } + + @Test + public void arrayDelayErrorMultipleErrors() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + + Flowable.concatArrayDelayError(Flowable.error(new IOException()), Flowable.error(new TestException())) + .subscribe(ts); + + ts.assertFailure(CompositeException.class); + + TestHelper.assertCompositeExceptions(ts, IOException.class, TestException.class); + } + + @Test + public void arrayDelayErrorMultipleNullErrors() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + + Flowable.concatArrayDelayError(null, null) + .subscribe(ts); + + ts.assertFailure(CompositeException.class); + + TestHelper.assertCompositeExceptions(ts, NullPointerException.class, NullPointerException.class); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithCompletableTest.java index fcf199dfd01..845c814dbcf 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithMaybeTest.java index a855c09c265..5b45eafc7f3 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithMaybeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithMaybeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithSingleTest.java index 4301746a86d..8a7ed3cd658 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableConcatWithSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCountTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCountTest.java index 158a3232f0f..608138e3572 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCountTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCountTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCreateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCreateTest.java index d0c0adfb70d..4c3b7354764 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCreateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableCreateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,33 +17,22 @@ import java.io.IOException; import java.util.*; +import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Cancellable; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; public class FlowableCreateTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void sourceNull() { - Flowable.create(null, BackpressureStrategy.BUFFER); - } - - @Test(expected = NullPointerException.class) - public void modeNull() { - Flowable.create(new FlowableOnSubscribe() { - @Override - public void subscribe(FlowableEmitter s) throws Exception { } - }, null); - } - @Test public void basic() { List errors = TestHelper.trackPluginErrors(); @@ -767,11 +756,6 @@ public void subscribe(FlowableEmitter e) throws Exception { } } - @Test(expected = NullPointerException.class) - public void nullArgument() { - Flowable.create(null, BackpressureStrategy.MISSING); - } - @Test public void onErrorCrash() { for (BackpressureStrategy m : BackpressureStrategy.values()) { @@ -1081,4 +1065,66 @@ public void subscribe(FlowableEmitter emitter) throws Exception { }, entry.getKey()).test().assertEmpty(); } } + + @Test + public void serializedMissingMoreWorkWithComplete() { + AtomicReference> ref = new AtomicReference<>(); + + Flowable.create(emitter -> { + emitter = emitter.serialize(); + ref.set(emitter); + assertEquals(Long.MAX_VALUE, emitter.requested()); + emitter.onNext(1); + }, BackpressureStrategy.MISSING) + .doOnNext(v -> { + if (v == 1) { + ref.get().onNext(2); + ref.get().onComplete(); + } + }) + .test() + .assertResult(1, 2); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.create(e -> { }, BackpressureStrategy.BUFFER)); + } + + @Test + public void tryOnErrorNull() { + Flowable.create(emitter -> emitter.tryOnError(null), BackpressureStrategy.MISSING) + .test() + .assertFailure(NullPointerException.class); + } + + @Test + public void serializedCompleteOnNext() { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.create(emitter -> { + emitter = emitter.serialize(); + + emitter.onComplete(); + emitter.onNext(1); + }, BackpressureStrategy.MISSING) + .subscribe(ts); + + ts.assertResult(); + } + + @Test + public void serializedCancelOnNext() { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.create(emitter -> { + emitter = emitter.serialize(); + + ts.cancel(); + emitter.onNext(1); + }, BackpressureStrategy.MISSING) + .subscribe(ts); + + ts.assertEmpty(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDebounceTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDebounceTest.java index bfb33f0e8e2..01122106c86 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDebounceTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDebounceTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,6 +21,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import io.reactivex.rxjava3.functions.Action; import org.junit.*; import org.mockito.InOrder; import org.reactivestreams.*; @@ -41,16 +42,86 @@ public class FlowableDebounceTest extends RxJavaTest { private TestScheduler scheduler; - private Subscriber Subscriber; + private Subscriber subscriber; private Scheduler.Worker innerScheduler; @Before public void before() { scheduler = new TestScheduler(); - Subscriber = TestHelper.mockSubscriber(); + subscriber = TestHelper.mockSubscriber(); innerScheduler = scheduler.createWorker(); } + @Test + public void debounceWithOnDroppedCallbackWithEx() throws Throwable { + Flowable source = Flowable.unsafeCreate(new Publisher() { + @Override + public void subscribe(Subscriber subscriber) { + subscriber.onSubscribe(new BooleanSubscription()); + publishNext(subscriber, 100, "one"); // Should be skipped since "two" will arrive before the timeout expires. + publishNext(subscriber, 400, "two"); // Should be published since "three" will arrive after the timeout expires. + publishNext(subscriber, 900, "three"); // Should be skipped since "four" will arrive before the timout expires. + publishNext(subscriber, 999, "four"); // Should be skipped since onComplete will arrive before the timeout expires. + publishCompleted(subscriber, 1000); // Should be published as soon as the timeout expires. + } + }); + + Action whenDisposed = mock(Action.class); + + Flowable sampled = source + .doOnCancel(whenDisposed) + .debounce(400, TimeUnit.MILLISECONDS, scheduler, e -> { + if ("three".equals(e)) { + throw new TestException("forced"); + } + }); + sampled.subscribe(subscriber); + + InOrder inOrder = inOrder(subscriber); + + scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); + inOrder.verify(subscriber, times(1)).onNext("two"); + inOrder.verify(subscriber, times(1)).onError(any(TestException.class)); + inOrder.verify(subscriber, times(0)).onNext("three"); + inOrder.verify(subscriber, times(0)).onNext("four"); + inOrder.verify(subscriber, times(0)).onComplete(); + inOrder.verifyNoMoreInteractions(); + verify(whenDisposed).run(); + } + + @Test + public void debounceWithOnDroppedCallback() { + Flowable source = Flowable.unsafeCreate(new Publisher() { + @Override + public void subscribe(Subscriber subscriber) { + subscriber.onSubscribe(new BooleanSubscription()); + publishNext(subscriber, 100, "one"); // Should be skipped since "two" will arrive before the timeout expires. + publishNext(subscriber, 400, "two"); // Should be published since "three" will arrive after the timeout expires. + publishNext(subscriber, 900, "three"); // Should be skipped since "four" will arrive before the timout expires. + publishNext(subscriber, 999, "four"); // Should be skipped since onComplete will arrive before the timeout expires. + publishCompleted(subscriber, 1000); // Should be published as soon as the timeout expires. + } + }); + + Observer dropCallbackObserver = TestHelper.mockObserver(); + Flowable sampled = source.debounce(400, TimeUnit.MILLISECONDS, scheduler, dropCallbackObserver::onNext); + sampled.subscribe(subscriber); + + scheduler.advanceTimeTo(0, TimeUnit.MILLISECONDS); + InOrder inOrder = inOrder(subscriber); + InOrder dropCallbackOrder = inOrder(dropCallbackObserver); + + // must go to 800 since it must be 400 after when two is sent, which is at 400 + scheduler.advanceTimeTo(800, TimeUnit.MILLISECONDS); + inOrder.verify(subscriber, times(1)).onNext("two"); + dropCallbackOrder.verify(dropCallbackObserver, times(1)).onNext("one"); + scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); + dropCallbackOrder.verify(dropCallbackObserver, times(1)).onNext("three"); + inOrder.verify(subscriber, times(1)).onComplete(); + inOrder.verifyNoMoreInteractions(); + dropCallbackOrder.verifyNoMoreInteractions(); + } + @Test public void debounceWithCompleted() { Flowable source = Flowable.unsafeCreate(new Publisher() { @@ -65,15 +136,15 @@ public void subscribe(Subscriber subscriber) { }); Flowable sampled = source.debounce(400, TimeUnit.MILLISECONDS, scheduler); - sampled.subscribe(Subscriber); + sampled.subscribe(subscriber); scheduler.advanceTimeTo(0, TimeUnit.MILLISECONDS); - InOrder inOrder = inOrder(Subscriber); + InOrder inOrder = inOrder(subscriber); // must go to 800 since it must be 400 after when two is sent, which is at 400 scheduler.advanceTimeTo(800, TimeUnit.MILLISECONDS); - inOrder.verify(Subscriber, times(1)).onNext("two"); + inOrder.verify(subscriber, times(1)).onNext("two"); scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); - inOrder.verify(Subscriber, times(1)).onComplete(); + inOrder.verify(subscriber, times(1)).onComplete(); inOrder.verifyNoMoreInteractions(); } @@ -97,13 +168,13 @@ public void subscribe(Subscriber subscriber) { }); Flowable sampled = source.debounce(200, TimeUnit.MILLISECONDS, scheduler); - sampled.subscribe(Subscriber); + sampled.subscribe(subscriber); scheduler.advanceTimeTo(0, TimeUnit.MILLISECONDS); - InOrder inOrder = inOrder(Subscriber); - inOrder.verify(Subscriber, times(0)).onNext(anyString()); + InOrder inOrder = inOrder(subscriber); + inOrder.verify(subscriber, times(0)).onNext(anyString()); scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); - inOrder.verify(Subscriber, times(1)).onComplete(); + inOrder.verify(subscriber, times(1)).onComplete(); inOrder.verifyNoMoreInteractions(); } @@ -121,15 +192,15 @@ public void subscribe(Subscriber subscriber) { }); Flowable sampled = source.debounce(400, TimeUnit.MILLISECONDS, scheduler); - sampled.subscribe(Subscriber); + sampled.subscribe(subscriber); scheduler.advanceTimeTo(0, TimeUnit.MILLISECONDS); - InOrder inOrder = inOrder(Subscriber); + InOrder inOrder = inOrder(subscriber); // 100 + 400 means it triggers at 500 scheduler.advanceTimeTo(500, TimeUnit.MILLISECONDS); - inOrder.verify(Subscriber).onNext("one"); + inOrder.verify(subscriber).onNext("one"); scheduler.advanceTimeTo(701, TimeUnit.MILLISECONDS); - inOrder.verify(Subscriber).onError(any(TestException.class)); + inOrder.verify(subscriber).onError(any(TestException.class)); inOrder.verifyNoMoreInteractions(); } @@ -530,7 +601,7 @@ public void timedBadRequest() { public void timedLateEmit() { TestSubscriber ts = new TestSubscriber<>(); DebounceTimedSubscriber sub = new DebounceTimedSubscriber<>( - ts, 1, TimeUnit.SECONDS, new TestScheduler().createWorker()); + ts, 1, TimeUnit.SECONDS, new TestScheduler().createWorker(), null); sub.onSubscribe(new BooleanSubscription()); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDefaultIfEmptyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDefaultIfEmptyTest.java index dadec04fbed..fc2c7e15a88 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDefaultIfEmptyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDefaultIfEmptyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDeferTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDeferTest.java index 8a1b48d4e97..caec2443fc4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDeferTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDeferTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelaySubscriptionOtherTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelaySubscriptionOtherTest.java index fde11b5ea1f..57a8af4586f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelaySubscriptionOtherTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelaySubscriptionOtherTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import java.util.concurrent.*; @@ -308,11 +309,6 @@ public void accept(Subscription s) { Assert.assertFalse(subscribed.get()); } - @Test(expected = NullPointerException.class) - public void otherNull() { - Flowable.just(1).delaySubscription((Flowable)null); - } - @Test public void badSourceOther() { TestHelper.checkBadSourceFlowable(new Function, Object>() { @@ -348,4 +344,19 @@ public void subscribe(FlowableEmitter emitter) throws Exception { exec.shutdown(); } } + + @Test + public void doubleOnSubscribeMain() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.delaySubscription(Flowable.empty())); + } + + @Test + public void doubleOnSubscribeOther() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> PublishProcessor.create().delaySubscription(f)); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(PublishProcessor.create().delaySubscription(Flowable.empty())); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelayTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelayTest.java index 79740ee44c9..4d67594a177 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelayTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDelayTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,6 +20,7 @@ import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.LockSupport; import org.junit.*; import org.mockito.InOrder; @@ -28,6 +29,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.disposables.SequentialDisposable; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.schedulers.*; @@ -1030,4 +1032,38 @@ public Publisher apply(Integer t) throws Exception { .to(TestHelper.testConsumer()) .assertFailureAndMessage(NullPointerException.class, "The itemDelay returned a null Publisher"); } + + @Test + public void cancelShouldPreventRandomSubsequentEmissions() { + for (int attempt = 1; attempt < 100; attempt ++) { + + SequentialDisposable disposable = new SequentialDisposable(); + ConcurrentLinkedQueue sink = new ConcurrentLinkedQueue<>(); + + disposable.replace( + Flowable.range(1, 10) + .delay(1, TimeUnit.MICROSECONDS, Schedulers.computation(), true) + .doOnNext(v -> { + if (v == 1) { + Schedulers.computation().scheduleDirect(disposable::dispose); + } + sink.offer(v); + }) + .subscribe()); + + LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1)); + + Integer last = null; + + while (!sink.isEmpty()) { + Integer current = sink.poll(); + + if (last != null && last + 1 != current) { + fail("Emission hole: " + last + " -> " + current); + } + + last = current; + } + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDematerializeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDematerializeTest.java index d4578db5291..89a14546141 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDematerializeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDematerializeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -223,7 +223,7 @@ protected void subscribeActual(Subscriber> subscrib } @Test - public void nonNotificationInstanceAfterDispose() { + public void notificationInstanceAfterDispose() { new Flowable>() { @Override protected void subscribeActual(Subscriber> subscriber) { @@ -236,4 +236,20 @@ protected void subscribeActual(Subscriber> subscrib .test() .assertResult(); } + + @Test + @SuppressWarnings("unchecked") + public void nonNotificationInstanceAfterDispose() { + new Flowable() { + @Override + protected void subscribeActual(Subscriber subscriber) { + subscriber.onSubscribe(new BooleanSubscription()); + subscriber.onNext(Notification.createOnComplete()); + subscriber.onNext(1); + } + } + .dematerialize(v -> (Notification)v) + .test() + .assertResult(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDetachTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDetachTest.java index 3c87bfeb9af..23d895ca08b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDetachTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDetachTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import java.lang.ref.WeakReference; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinctTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinctTest.java index 87d5cda476b..362283c7193 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinctTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinctTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,9 +27,10 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.internal.util.ExceptionHelper; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.UnicastProcessor; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinctUntilChangedTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinctUntilChangedTest.java index 9d9aa55fd84..00525b562bc 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinctUntilChangedTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDistinctUntilChangedTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -28,8 +28,8 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.subscribers.TestSubscriber; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoAfterNextTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoAfterNextTest.java index 47f0d74e0b5..1e36eee49f6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoAfterNextTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoAfterNextTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,7 +23,7 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Consumer; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.processors.UnicastProcessor; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; @@ -133,11 +133,6 @@ public void asyncFused() { assertEquals(Arrays.asList(-1, -2, -3, -4, -5), values); } - @Test(expected = NullPointerException.class) - public void consumerNull() { - Flowable.just(1).doAfterNext(null); - } - @Test public void justConditional() { Flowable.just(1) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoAfterTerminateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoAfterTerminateTest.java index cee677cf41d..ab1a3bd8ab4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoAfterTerminateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoAfterTerminateTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import static org.junit.Assert.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoFinallyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoFinallyTest.java index 8249383dca3..79cba18b3d3 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoFinallyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoFinallyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,7 +24,8 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.*; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.UnicastProcessor; import io.reactivex.rxjava3.testsupport.*; @@ -208,7 +209,7 @@ public void syncFusedConditional() { Flowable.range(1, 5) .doFinally(this) - .filter(Functions.alwaysTrue()) + .compose(TestHelper.conditional()) .subscribe(ts); ts.assertFusionMode(QueueFuseable.SYNC) @@ -237,7 +238,7 @@ public void nonFusedConditional() { Flowable.range(1, 5).hide() .doFinally(this) - .filter(Functions.alwaysTrue()) + .compose(TestHelper.conditional()) .subscribe(ts); ts.assertFusionMode(QueueFuseable.NONE) @@ -252,7 +253,7 @@ public void syncFusedBoundaryConditional() { Flowable.range(1, 5) .doFinally(this) - .filter(Functions.alwaysTrue()) + .compose(TestHelper.conditional()) .subscribe(ts); ts.assertFusionMode(QueueFuseable.NONE) @@ -270,7 +271,7 @@ public void asyncFusedConditional() { up .doFinally(this) - .filter(Functions.alwaysTrue()) + .compose(TestHelper.conditional()) .subscribe(ts); ts.assertFusionMode(QueueFuseable.ASYNC) @@ -288,7 +289,7 @@ public void asyncFusedBoundaryConditional() { up .doFinally(this) - .filter(Functions.alwaysTrue()) + .compose(TestHelper.conditional()) .subscribe(ts); ts.assertFusionMode(QueueFuseable.NONE) @@ -297,11 +298,6 @@ public void asyncFusedBoundaryConditional() { assertEquals(1, calls); } - @Test(expected = NullPointerException.class) - public void nullAction() { - Flowable.just(1).doFinally(null); - } - @Test public void actionThrows() { List errors = TestHelper.trackPluginErrors(); @@ -517,4 +513,31 @@ public void run() throws Exception { assertEquals(Arrays.asList("onNext", "onComplete", "finally"), list); } + + @Test + public void fusionRejected() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.ANY); + + TestHelper.rejectFlowableFusion() + .doFinally(() -> { }) + .subscribeWith(ts); + + ts.assertFuseable() + .assertFusionMode(QueueFuseable.NONE); + } + + @Test + public void fusionRejectedConditional() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.ANY); + + TestHelper.rejectFlowableFusion() + .doFinally(() -> { }) + .compose(TestHelper.conditional()) + .subscribeWith(ts); + + ts.assertFuseable() + .assertFusionMode(QueueFuseable.NONE); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnEachTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnEachTest.java index fc346086b62..484d62c19e2 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnEachTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnEachTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -29,8 +29,9 @@ import io.reactivex.rxjava3.flowables.ConnectableFlowable; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.UnicastProcessor; import io.reactivex.rxjava3.subscribers.TestSubscriber; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnLifecycleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnLifecycleTest.java index 524a0b5acb4..e1df09d7ee2 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnLifecycleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnLifecycleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnRequestTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnRequestTest.java index b07470a3981..3e123089dcc 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnRequestTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnRequestTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnSubscribeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnSubscribeTest.java index c9ea4359d17..6dff7a53219 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnSubscribeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnSubscribeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnUnsubscribeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnUnsubscribeTest.java index eab0324ba85..d060928deea 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnUnsubscribeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableDoOnUnsubscribeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtTest.java index 56297cbe057..0e36e075a85 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableElementAtTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFilterTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFilterTest.java index 586a7b56c28..4b62f1e2a46 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFilterTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFilterTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -28,8 +28,9 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.subscribers.TestSubscriber; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFirstTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFirstTest.java index efcdb290c0e..b6100ddeb3c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFirstTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFirstTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapCompletableTest.java index 1c87d6f3b39..5e4e5c8f774 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,18 +16,19 @@ import static org.junit.Assert.*; import java.util.List; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import org.junit.Test; import org.reactivestreams.Subscription; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; -import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subscribers.TestSubscriber; @@ -510,6 +511,23 @@ protected void subscribeActual(CompletableObserver observer) { @Test public void delayErrorMaxConcurrency() { + Flowable.range(1, 3) + .flatMapCompletable(new Function() { + @Override + public CompletableSource apply(Integer v) throws Exception { + if (v == 2) { + return Completable.error(new TestException()); + } + return Completable.complete(); + } + }, true, 1) + .toFlowable() + .test() + .assertFailure(TestException.class); + } + + @Test + public void delayErrorMaxConcurrencyCompletable() { Flowable.range(1, 3) .flatMapCompletable(new Function() { @Override @@ -570,4 +588,59 @@ public Completable apply(Integer v) throws Throwable { } }); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.flatMapCompletable(v -> Completable.never()).toFlowable()); + } + + @Test + public void doubleOnSubscribeCompletable() { + TestHelper.checkDoubleOnSubscribeFlowableToCompletable(f -> f.flatMapCompletable(v -> Completable.never())); + } + + @Test + public void cancelWhileMapping() throws Throwable { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + PublishProcessor pp1 = PublishProcessor.create(); + + TestSubscriber ts = new TestSubscriber<>(); + CountDownLatch cdl = new CountDownLatch(1); + + pp1.flatMapCompletable(v -> { + TestHelper.raceOther(() -> { + ts.cancel(); + }, cdl); + return Completable.complete(); + }) + .toFlowable() + .subscribe(ts); + + pp1.onNext(1); + + cdl.await(); + } + } + + @Test + public void cancelWhileMappingCompletable() throws Throwable { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + PublishProcessor pp1 = PublishProcessor.create(); + + TestObserver to = new TestObserver<>(); + CountDownLatch cdl = new CountDownLatch(1); + + pp1.flatMapCompletable(v -> { + TestHelper.raceOther(() -> { + to.dispose(); + }, cdl); + return Completable.complete(); + }) + .subscribe(to); + + pp1.onNext(1); + + cdl.await(); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapMaybeTest.java index 8faad86fef1..a377761f0cf 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapMaybeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapMaybeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ import org.reactivestreams.Subscriber; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.functions.Functions; @@ -30,6 +30,7 @@ import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.subjects.MaybeSubject; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; @@ -641,4 +642,57 @@ public Maybe apply(Integer v) throws Throwable { } }); } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().flatMapMaybe(v -> Maybe.never())); + } + + @Test + public void successRace() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + MaybeSubject ss1 = MaybeSubject.create(); + MaybeSubject ss2 = MaybeSubject.create(); + + TestSubscriber ts = Flowable.just(ss1, ss2).flatMapMaybe(v -> v) + .test(); + + TestHelper.race( + () -> ss1.onSuccess(1), + () -> ss2.onSuccess(1) + ); + + ts.assertResult(1, 1); + } + } + + @Test + public void successCompleteRace() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + MaybeSubject ss1 = MaybeSubject.create(); + MaybeSubject ss2 = MaybeSubject.create(); + + TestSubscriber ts = Flowable.just(ss1, ss2).flatMapMaybe(v -> v) + .test(); + + TestHelper.race( + () -> ss1.onSuccess(1), + () -> ss2.onComplete() + ); + + ts.assertResult(1); + } + } + + @Test + public void successShortcut() { + MaybeSubject ss1 = MaybeSubject.create(); + + TestSubscriber ts = Flowable.just(ss1).hide().flatMapMaybe(v -> v) + .test(); + + ss1.onSuccess(1); + + ts.assertResult(1); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapSingleTest.java index 1a0cd3854ff..b13e8316af7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ import org.reactivestreams.Subscriber; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.functions.Functions; @@ -30,6 +30,7 @@ import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.subjects.SingleSubject; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; @@ -541,4 +542,39 @@ public Single apply(Integer v) throws Throwable { } }); } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().flatMapSingle(v -> Single.never())); + } + + @Test + public void successRace() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + SingleSubject ss1 = SingleSubject.create(); + SingleSubject ss2 = SingleSubject.create(); + + TestSubscriber ts = Flowable.just(ss1, ss2).flatMapSingle(v -> v) + .test(); + + TestHelper.race( + () -> ss1.onSuccess(1), + () -> ss2.onSuccess(1) + ); + + ts.assertResult(1, 1); + } + } + + @Test + public void successShortcut() { + SingleSubject ss1 = SingleSubject.create(); + + TestSubscriber ts = Flowable.just(ss1).hide().flatMapSingle(v -> v) + .test(); + + ss1.onSuccess(1); + + ts.assertResult(1); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapTest.java index 068f652db06..be94c5e57c7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlatMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,19 +17,22 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; +import java.io.IOException; import java.util.*; import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.*; import org.junit.*; import org.reactivestreams.*; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; @@ -1116,4 +1119,387 @@ public Publisher apply(Integer v) throws Throwable { } }); } + + @Test + public void mainErrorsInnerCancelled() { + PublishProcessor pp1 = PublishProcessor.create(); + PublishProcessor pp2 = PublishProcessor.create(); + + pp1 + .flatMap(v -> pp2) + .test(); + + pp1.onNext(1); + assertTrue("No subscribers?", pp2.hasSubscribers()); + + pp1.onError(new TestException()); + + assertFalse("Has subscribers?", pp2.hasSubscribers()); + } + + @Test + public void innerErrorsMainCancelled() { + PublishProcessor pp1 = PublishProcessor.create(); + PublishProcessor pp2 = PublishProcessor.create(); + + pp1 + .flatMap(v -> pp2) + .test(); + + pp1.onNext(1); + assertTrue("No subscribers?", pp2.hasSubscribers()); + + pp2.onError(new TestException()); + + assertFalse("Has subscribers?", pp1.hasSubscribers()); + } + + @Test + public void innerIsDisposed() { + FlowableFlatMap.InnerSubscriber inner = new FlowableFlatMap.InnerSubscriber<>(null, 10, 0L); + + assertFalse(inner.isDisposed()); + + inner.dispose(); + + assertTrue(inner.isDisposed()); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().flatMap(v -> Flowable.never())); + } + + @Test + public void signalsAfterMapperCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + new Flowable() { + @Override + protected void subscribeActual(@NonNull Subscriber s) { + s.onSubscribe(new BooleanSubscription()); + s.onNext(1); + s.onNext(2); + s.onComplete(); + s.onError(new IOException()); + } + } + .flatMap(v -> { + throw new TestException(); + }) + .test() + .assertFailure(TestException.class); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + }); + } + + @Test + public void scalarQueueTerminate() { + PublishProcessor pp = PublishProcessor.create(); + TestSubscriber ts = new TestSubscriber<>(); + + pp + .flatMap(v -> Flowable.just(v)) + .doOnNext(v -> { + if (v == 1) { + pp.onNext(2); + pp.onNext(3); + } + }) + .take(2) + .subscribe(ts); + + pp.onNext(1); + + ts.assertResult(1, 2); + } + + @Test + public void scalarQueueCompleteMain() throws Exception { + PublishProcessor pp = PublishProcessor.create(); + TestSubscriber ts = new TestSubscriber<>(); + CountDownLatch cdl = new CountDownLatch(1); + pp + .flatMap(v -> Flowable.just(v)) + .doOnNext(v -> { + if (v == 1) { + pp.onNext(2); + TestHelper.raceOther(() -> pp.onComplete(), cdl); + } + }) + .subscribe(ts); + + pp.onNext(1); + + cdl.await(); + ts.assertResult(1, 2); + } + + @Test + public void fusedInnerCrash() { + UnicastProcessor up = UnicastProcessor.create(); + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = Flowable.just( + pp, + up.map(v -> { + if (v == 10) { + throw new TestException(); + } + return v; + }) + .compose(TestHelper.flowableStripBoundary()) + ) + .flatMap(v -> v, true) + .doOnNext(v -> { + if (v == 1) { + pp.onNext(2); + up.onNext(10); + } + }) + .test(); + + pp.onNext(1); + pp.onComplete(); + + ts.assertFailure(TestException.class, 1, 2); + } + + @Test + public void fusedInnerCrash2() { + UnicastProcessor up = UnicastProcessor.create(); + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = Flowable.just( + up.map(v -> { + if (v == 10) { + throw new TestException(); + } + return v; + }) + .compose(TestHelper.flowableStripBoundary()) + , pp + ) + .flatMap(v -> v, true) + .doOnNext(v -> { + if (v == 1) { + pp.onNext(2); + up.onNext(10); + } + }) + .test(); + + pp.onNext(1); + pp.onComplete(); + + ts.assertFailure(TestException.class, 1, 2); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.flatMap(v -> Flowable.never())); + } + + @Test + public void allConcurrency() { + Flowable.just(1) + .hide() + .flatMap(v -> Flowable.just(2).hide(), Integer.MAX_VALUE) + .test() + .assertResult(2); + } + + @Test + public void allConcurrencyScalarInner() { + Flowable.just(1) + .hide() + .flatMap(v -> Flowable.just(2), Integer.MAX_VALUE) + .test() + .assertResult(2); + } + + @Test + public void allConcurrencyScalarInnerEmpty() { + Flowable.just(1) + .hide() + .flatMap(v -> Flowable.empty(), Integer.MAX_VALUE) + .test() + .assertResult(); + } + + static final class ScalarEmptyCancel extends Flowable implements Supplier { + final TestSubscriber ts; + + ScalarEmptyCancel(TestSubscriber ts) { + this.ts = ts; + } + + @Override + public @NonNull Integer get() throws Throwable { + ts.cancel(); + return null; + } + + @Override + protected void subscribeActual(@NonNull Subscriber<@NonNull ? super @NonNull Integer> subscriber) { + EmptySubscription.complete(subscriber); + } + } + + @Test + public void someConcurrencyScalarInnerCancel() { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.just(1) + .hide() + .flatMap(v -> new ScalarEmptyCancel(ts)) + .subscribeWith(ts) + .assertEmpty(); + } + + @Test + public void allConcurrencyBackpressured() { + Flowable.just(1) + .hide() + .flatMap(v -> Flowable.just(2), Integer.MAX_VALUE) + .test(0L) + .assertEmpty() + .requestMore(1) + .assertResult(2); + } + + @Test + public void someConcurrencyInnerScalarCancel() { + Flowable.just(1) + .hide() + .flatMap(v -> Flowable.just(2), 2) + .takeUntil(v -> true) + .test() + .assertResult(2); + } + + @Test + public void scalarInnerOuterOverflow() { + new Flowable() { + @Override + protected void subscribeActual(@NonNull Subscriber<@NonNull ? super @NonNull Integer> subscriber) { + subscriber.onSubscribe(new BooleanSubscription()); + subscriber.onNext(1); + subscriber.onNext(2); + subscriber.onNext(3); + } + } + .flatMap(v -> Flowable.just(v), 1) + .test(0L) + .assertFailure(QueueOverflowException.class); + } + + @Test + public void scalarInnerOuterOverflowSlowPath() { + AtomicReference> ref = new AtomicReference<>(); + new Flowable() { + @Override + protected void subscribeActual(@NonNull Subscriber<@NonNull ? super @NonNull Integer> subscriber) { + subscriber.onSubscribe(new BooleanSubscription()); + ref.set(subscriber); + subscriber.onNext(1); + } + } + .flatMap(v -> Flowable.just(v), 1) + .doOnNext(v -> { + if (v == 1) { + ref.get().onNext(2); + ref.get().onNext(3); + } + }) + .test() + .assertFailure(QueueOverflowException.class, 1); + } + + @Test + public void innerFastPathEmitOverflow() { + Flowable.just(1) + .hide() + .flatMap(v -> new Flowable() { + @Override + protected void subscribeActual(@NonNull Subscriber<@NonNull ? super @NonNull Integer> subscriber) { + subscriber.onSubscribe(new BooleanSubscription()); + subscriber.onNext(1); + subscriber.onNext(2); + subscriber.onNext(3); + } + }, false, 1, 1) + .test(0L) + .assertFailure(QueueOverflowException.class); + } + + @Test + public void takeFromScalarQueue() { + Flowable.just(1) + .hide() + .flatMap(v -> Flowable.just(2), 2) + .takeUntil(v -> true) + .test(0L) + .requestMore(2) + .assertResult(2); + } + + @Test + public void scalarInnerQueueEmpty() { + Flowable.just(1) + .concatWith(Flowable.never()) + .hide() + .flatMap(v -> Flowable.just(2), 2) + .test(0L) + .requestMore(2) + .assertValuesOnly(2); + } + + @Test + public void innerCompletesAfterOnNextInDrainThenCancels() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = new TestSubscriber<>(0L); + + Flowable.just(1) + .hide() + .flatMap(v -> pp) + .doOnNext(v -> { + if (v == 1) { + pp.onComplete(); + ts.cancel(); + } + }) + .subscribe(ts); + + pp.onNext(1); + + ts + .requestMore(1) + .assertValuesOnly(1); + } + + @Test(timeout = 5000) + public void mixedScalarAsync() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + Flowable + .range(0, 20) + .flatMap( + integer -> { + if (integer % 5 != 0) { + return Flowable + .just(integer); + } + + return Flowable + .just(-integer) + .observeOn(Schedulers.computation()); + }, + false, + 1 + ) + .ignoreElements() + .blockingAwait(); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlattenIterableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlattenIterableTest.java index c65cf4b5b47..2cb9392e19c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlattenIterableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFlattenIterableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,10 +26,11 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.operators.flowable.FlowableFlattenIterable.FlattenIterableSubscriber; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.internal.util.ExceptionHelper; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.subscribers.TestSubscriber; @@ -813,7 +814,7 @@ protected void subscribeActual(Subscriber s) { } .flatMapIterable(Functions.justFunction(Arrays.asList(1)), 1) .test(0L) - .assertFailure(MissingBackpressureException.class); + .assertFailure(QueueOverflowException.class); } @Test diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableForEachTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableForEachTest.java index d9ff63257ca..e74d5caf261 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableForEachTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableForEachTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,6 +22,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.testsupport.TestHelper; public class FlowableForEachTest extends RxJavaTest { @@ -72,4 +73,11 @@ public void accept(Throwable e) throws Exception { assertEquals(Arrays.asList(1, 2, 3, 4, 5, 100), list); } + @Test + public void dispose() { + TestHelper.checkDisposed( + Flowable.never() + .forEachWhile(v -> true) + ); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromActionTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromActionTest.java new file mode 100644 index 00000000000..5395ae30680 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromActionTest.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.subscribers.TestSubscriber; +import io.reactivex.rxjava3.testsupport.*; + +public class FlowableFromActionTest extends RxJavaTest { + @Test + public void fromAction() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Flowable.fromAction(new Action() { + @Override + public void run() throws Exception { + atomicInteger.incrementAndGet(); + } + }) + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + } + + @Test + public void fromActionTwice() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Action run = new Action() { + @Override + public void run() throws Exception { + atomicInteger.incrementAndGet(); + } + }; + + Flowable.fromAction(run) + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + + Flowable.fromAction(run) + .test() + .assertResult(); + + assertEquals(2, atomicInteger.get()); + } + + @Test + public void fromActionInvokesLazy() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Flowable source = Flowable.fromAction(new Action() { + @Override + public void run() throws Exception { + atomicInteger.incrementAndGet(); + } + }); + + assertEquals(0, atomicInteger.get()); + + source + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + } + + @Test + public void fromActionThrows() { + Flowable.fromAction(new Action() { + @Override + public void run() throws Exception { + throw new UnsupportedOperationException(); + } + }) + .test() + .assertFailure(UnsupportedOperationException.class); + } + + @SuppressWarnings("unchecked") + @Test + public void callable() throws Throwable { + final int[] counter = { 0 }; + + Flowable m = Flowable.fromAction(new Action() { + @Override + public void run() throws Exception { + counter[0]++; + } + }); + + assertTrue(m.getClass().toString(), m instanceof Supplier); + + assertNull(((Supplier)m).get()); + + assertEquals(1, counter[0]); + } + + @Test + public void noErrorLoss() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + final CountDownLatch cdl1 = new CountDownLatch(1); + final CountDownLatch cdl2 = new CountDownLatch(1); + + TestSubscriber ts = Flowable.fromAction(new Action() { + @Override + public void run() throws Exception { + cdl1.countDown(); + cdl2.await(5, TimeUnit.SECONDS); + } + }).subscribeOn(Schedulers.single()).test(); + + assertTrue(cdl1.await(5, TimeUnit.SECONDS)); + + ts.cancel(); + + int timeout = 10; + + while (timeout-- > 0 && errors.isEmpty()) { + Thread.sleep(100); + } + + TestHelper.assertUndeliverable(errors, 0, InterruptedException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void disposedUpfront() throws Throwable { + Action run = mock(Action.class); + + Flowable.fromAction(run) + .test(1L, true) + .assertEmpty(); + + verify(run, never()).run(); + } + + @Test + public void cancelWhileRunning() { + final TestSubscriber ts = new TestSubscriber<>(); + + Flowable.fromAction(new Action() { + @Override + public void run() throws Exception { + ts.cancel(); + } + }) + .subscribeWith(ts) + .assertEmpty(); + + assertTrue(ts.isCancelled()); + } + + @Test + public void asyncFused() throws Throwable { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.ASYNC); + + Action action = mock(Action.class); + + Flowable.fromAction(action) + .subscribe(ts); + + ts.assertFusionMode(QueueFuseable.ASYNC) + .assertResult(); + + verify(action).run(); + } + + @Test + public void syncFusedRejected() throws Throwable { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.SYNC); + + Action action = mock(Action.class); + + Flowable.fromAction(action) + .subscribe(ts); + + ts.assertFusionMode(QueueFuseable.NONE) + .assertResult(); + + verify(action).run(); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromArrayTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromArrayTest.java index d4dda817540..d3195ad8b22 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromArrayTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromArrayTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.operators.flowable; @@ -21,7 +18,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.functions.Predicate; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.ScalarSupplier; +import io.reactivex.rxjava3.operators.ScalarSupplier; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.TestHelper; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCallableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCallableTest.java index f8f3ed670c9..b603fd2d9b3 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCallableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCallableTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.operators.flowable; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCompletableTest.java new file mode 100644 index 00000000000..fc8e4ec977f --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromCompletableTest.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.fuseable.*; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.subscribers.TestSubscriber; +import io.reactivex.rxjava3.testsupport.*; + +public class FlowableFromCompletableTest extends RxJavaTest { + @Test + public void fromCompletable() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Flowable.fromCompletable(Completable.fromAction(new Action() { + @Override + public void run() throws Exception { + atomicInteger.incrementAndGet(); + } + })) + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + } + + @Test + public void fromCompletableTwice() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Action run = new Action() { + @Override + public void run() throws Exception { + atomicInteger.incrementAndGet(); + } + }; + + Flowable.fromCompletable(Completable.fromAction(run)) + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + + Flowable.fromCompletable(Completable.fromAction(run)) + .test() + .assertResult(); + + assertEquals(2, atomicInteger.get()); + } + + @Test + public void fromCompletableInvokesLazy() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Flowable source = Flowable.fromCompletable(Completable.fromAction(new Action() { + @Override + public void run() throws Exception { + atomicInteger.incrementAndGet(); + } + })); + + assertEquals(0, atomicInteger.get()); + + source + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + } + + @Test + public void fromCompletableThrows() { + Flowable.fromCompletable(Completable.fromAction(new Action() { + @Override + public void run() throws Exception { + throw new UnsupportedOperationException(); + } + })) + .test() + .assertFailure(UnsupportedOperationException.class); + } + + @Test + public void noErrorLoss() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + final CountDownLatch cdl1 = new CountDownLatch(1); + final CountDownLatch cdl2 = new CountDownLatch(1); + + TestSubscriber ts = Flowable.fromCompletable(Completable.fromAction(new Action() { + @Override + public void run() throws Exception { + cdl1.countDown(); + cdl2.await(5, TimeUnit.SECONDS); + } + })) + .subscribeOn(Schedulers.single()).test(); + + assertTrue(cdl1.await(5, TimeUnit.SECONDS)); + + ts.cancel(); + + int timeout = 10; + + while (timeout-- > 0 && errors.isEmpty()) { + Thread.sleep(100); + } + + TestHelper.assertUndeliverable(errors, 0, InterruptedException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void disposedUpfront() throws Throwable { + Action run = mock(Action.class); + + Flowable.fromCompletable(Completable.fromAction(run)) + .test(1L, true) + .assertEmpty(); + + verify(run, never()).run(); + } + + @Test + public void cancelWhileRunning() { + final TestSubscriber ts = new TestSubscriber<>(); + + Flowable.fromCompletable(Completable.fromAction(new Action() { + @Override + public void run() throws Exception { + ts.cancel(); + } + })) + .subscribeWith(ts) + .assertEmpty(); + + assertTrue(ts.isCancelled()); + } + + @Test + public void asyncFused() throws Throwable { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.ASYNC); + + Action action = mock(Action.class); + + Flowable.fromCompletable(Completable.fromAction(action)) + .subscribe(ts); + + ts.assertFusionMode(QueueFuseable.ASYNC) + .assertResult(); + + verify(action).run(); + } + + @Test + public void syncFusedRejected() throws Throwable { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.SYNC); + + Action action = mock(Action.class); + + Flowable.fromCompletable(Completable.fromAction(action)) + .subscribe(ts); + + ts.assertFusionMode(QueueFuseable.NONE) + .assertResult(); + + verify(action).run(); + } + + @Test + public void upstream() { + Flowable f = Flowable.fromCompletable(Completable.never()); + assertTrue(f instanceof HasUpstreamCompletableSource); + assertSame(Completable.never(), ((HasUpstreamCompletableSource)f).source()); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromIterableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromIterableTest.java index 6385d58d956..5fe804a3102 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromIterableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromIterableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,18 +19,21 @@ import java.util.*; import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.*; import org.junit.Test; import org.mockito.Mockito; import org.reactivestreams.*; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.util.CrashingIterable; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subscribers.*; @@ -38,11 +41,6 @@ public class FlowableFromIterableTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void nullValue() { - Flowable.fromIterable(null); - } - @Test public void listIterable() { Flowable flowable = Flowable.fromIterable(Arrays. asList("one", "two", "three")); @@ -967,4 +965,259 @@ public void remove() { .assertNoErrors() .assertNotComplete(); } + + @Test + public void hasNextCancelsAndCompletesFastPath() { + final TestSubscriber ts = new TestSubscriber<>(); + + Flowable.fromIterable(new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + int count; + + @Override + public boolean hasNext() { + if (++count == 2) { + ts.cancel(); + return false; + } + return true; + } + + @Override + public Integer next() { + return 1; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }) + .subscribe(ts); + + ts.assertValue(1) + .assertNoErrors() + .assertNotComplete(); + } + + @Test + public void hasNextCancelsAndCompletesSlowPath() { + final TestSubscriber ts = new TestSubscriber<>(10L); + + Flowable.fromIterable(new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + int count; + + @Override + public boolean hasNext() { + if (++count == 2) { + ts.cancel(); + return false; + } + return true; + } + + @Override + public Integer next() { + return 1; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }) + .subscribe(ts); + + ts.assertValue(1) + .assertNoErrors() + .assertNotComplete(); + } + + @Test + public void hasNextCancelsAndCompletesFastPathConditional() { + final TestSubscriber ts = new TestSubscriber<>(); + + Flowable.fromIterable(new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + int count; + + @Override + public boolean hasNext() { + if (++count == 2) { + ts.cancel(); + return false; + } + return true; + } + + @Override + public Integer next() { + return 1; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }) + .filter(v -> true) + .subscribe(ts); + + ts.assertValue(1) + .assertNoErrors() + .assertNotComplete(); + } + + @Test + public void hasNextCancelsAndCompletesSlowPathConditional() { + final TestSubscriber ts = new TestSubscriber<>(10); + + Flowable.fromIterable(new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + int count; + + @Override + public boolean hasNext() { + if (++count == 2) { + ts.cancel(); + return false; + } + return true; + } + + @Override + public Integer next() { + return 1; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }) + .filter(v -> true) + .subscribe(ts); + + ts.assertValue(1) + .assertNoErrors() + .assertNotComplete(); + } + + @Test + public void fusedPoll() throws Throwable { + AtomicReference> queue = new AtomicReference<>(); + + Flowable.fromIterable(Arrays.asList(1)) + .subscribe(new FlowableSubscriber() { + @Override + public void onSubscribe(@NonNull Subscription s) { + queue.set((SimpleQueue)s); + ((QueueSubscription)s).requestFusion(QueueFuseable.ANY); + } + + @Override + public void onNext(Integer t) { + } + + @Override + public void onError(Throwable t) { + } + + @Override + public void onComplete() { + } + }); + + SimpleQueue q = queue.get(); + + assertFalse(q.isEmpty()); + + assertEquals(1, q.poll()); + + assertTrue(q.isEmpty()); + + q.clear(); + + assertTrue(q.isEmpty()); + } + + @Test + public void disposeWhileIteratorNext() { + final TestSubscriber ts = new TestSubscriber<>(10); + + Flowable.fromIterable(new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + @Override + public boolean hasNext() { + return true; + } + + @Override + public Integer next() { + ts.cancel(); + return 1; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }) + .subscribe(ts); + + ts.assertEmpty(); + } + + @Test + public void disposeWhileIteratorNextConditional() { + final TestSubscriber ts = new TestSubscriber<>(10); + + Flowable.fromIterable(new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + @Override + public boolean hasNext() { + return true; + } + + @Override + public Integer next() { + ts.cancel(); + return 1; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }) + .filter(v -> true) + .subscribe(ts); + + ts.assertEmpty(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromMaybeTest.java new file mode 100644 index 00000000000..d33b9f1e409 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromMaybeTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.subjects.MaybeSubject; +import io.reactivex.rxjava3.subscribers.TestSubscriber; +import io.reactivex.rxjava3.testsupport.TestSubscriberEx; + +public class FlowableFromMaybeTest extends RxJavaTest { + + @Test + public void success() { + Flowable.fromMaybe(Maybe.just(1).hide()) + .test() + .assertResult(1); + } + + @Test + public void empty() { + Flowable.fromMaybe(Maybe.empty().hide()) + .test() + .assertResult(); + } + + @Test + public void error() { + Flowable.fromMaybe(Maybe.error(new TestException()).hide()) + .test() + .assertFailure(TestException.class); + } + + @Test + public void cancelComposes() { + MaybeSubject ms = MaybeSubject.create(); + + TestSubscriber ts = Flowable.fromMaybe(ms) + .test(); + + ts.assertEmpty(); + + assertTrue(ms.hasObservers()); + + ts.cancel(); + + assertFalse(ms.hasObservers()); + } + + @Test + public void asyncFusion() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.ASYNC); + + Flowable.fromMaybe(Maybe.just(1)) + .subscribe(ts); + + ts + .assertFuseable() + .assertFusionMode(QueueFuseable.ASYNC) + .assertResult(1); + } + + @Test + public void syncFusionRejected() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.SYNC); + + Flowable.fromMaybe(Maybe.just(1)) + .subscribe(ts); + + ts + .assertFuseable() + .assertFusionMode(QueueFuseable.NONE) + .assertResult(1); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservableTest.java index 5689eadf494..f9f666d7fd4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -32,4 +32,14 @@ public void error() { .test() .assertFailure(TestException.class); } + + @Test + public void all() { + for (BackpressureStrategy mode : BackpressureStrategy.values()) { + Flowable.fromObservable(Observable.range(1, 5), mode) + .test() + .withTag("mode: " + mode) + .assertResult(1, 2, 3, 4, 5); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromRunnableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromRunnableTest.java new file mode 100644 index 00000000000..19ef5eb0180 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromRunnableTest.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.Supplier; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.subscribers.TestSubscriber; +import io.reactivex.rxjava3.testsupport.*; + +public class FlowableFromRunnableTest extends RxJavaTest { + @Test + public void fromRunnable() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Flowable.fromRunnable(new Runnable() { + @Override + public void run() { + atomicInteger.incrementAndGet(); + } + }) + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + } + + @Test + public void fromRunnableTwice() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Runnable run = new Runnable() { + @Override + public void run() { + atomicInteger.incrementAndGet(); + } + }; + + Flowable.fromRunnable(run) + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + + Flowable.fromRunnable(run) + .test() + .assertResult(); + + assertEquals(2, atomicInteger.get()); + } + + @Test + public void fromRunnableInvokesLazy() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Flowable source = Flowable.fromRunnable(new Runnable() { + @Override + public void run() { + atomicInteger.incrementAndGet(); + } + }); + + assertEquals(0, atomicInteger.get()); + + source + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + } + + @Test + public void fromRunnableThrows() { + Flowable.fromRunnable(new Runnable() { + @Override + public void run() { + throw new UnsupportedOperationException(); + } + }) + .test() + .assertFailure(UnsupportedOperationException.class); + } + + @SuppressWarnings("unchecked") + @Test + public void callable() throws Throwable { + final int[] counter = { 0 }; + + Flowable m = Flowable.fromRunnable(new Runnable() { + @Override + public void run() { + counter[0]++; + } + }); + + assertTrue(m.getClass().toString(), m instanceof Supplier); + + assertNull(((Supplier)m).get()); + + assertEquals(1, counter[0]); + } + + @Test + public void noErrorLoss() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + final CountDownLatch cdl1 = new CountDownLatch(1); + final CountDownLatch cdl2 = new CountDownLatch(1); + + TestSubscriber ts = Flowable.fromRunnable(new Runnable() { + @Override + public void run() { + cdl1.countDown(); + try { + cdl2.await(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + throw new TestException(e); + } + } + }).subscribeOn(Schedulers.single()).test(); + + assertTrue(cdl1.await(5, TimeUnit.SECONDS)); + + ts.cancel(); + + int timeout = 10; + + while (timeout-- > 0 && errors.isEmpty()) { + Thread.sleep(100); + } + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void disposedUpfront() throws Throwable { + Runnable run = mock(Runnable.class); + + Flowable.fromRunnable(run) + .test(1L, true) + .assertEmpty(); + + verify(run, never()).run(); + } + + @Test + public void cancelWhileRunning() { + final TestSubscriber ts = new TestSubscriber<>(); + + Flowable.fromRunnable(new Runnable() { + @Override + public void run() { + ts.cancel(); + } + }) + .subscribeWith(ts) + .assertEmpty(); + + assertTrue(ts.isCancelled()); + } + + @Test + public void asyncFused() throws Throwable { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.ASYNC); + + Runnable action = mock(Runnable.class); + + Flowable.fromRunnable(action) + .subscribe(ts); + + ts.assertFusionMode(QueueFuseable.ASYNC) + .assertResult(); + + verify(action).run(); + } + + @Test + public void syncFusedRejected() throws Throwable { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.SYNC); + + Runnable action = mock(Runnable.class); + + Flowable.fromRunnable(action) + .subscribe(ts); + + ts.assertFusionMode(QueueFuseable.NONE) + .assertResult(); + + verify(action).run(); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSingleTest.java new file mode 100644 index 00000000000..1aa15032990 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSingleTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.subjects.SingleSubject; +import io.reactivex.rxjava3.subscribers.TestSubscriber; +import io.reactivex.rxjava3.testsupport.TestSubscriberEx; + +public class FlowableFromSingleTest extends RxJavaTest { + + @Test + public void success() { + Flowable.fromSingle(Single.just(1).hide()) + .test() + .assertResult(1); + } + + @Test + public void error() { + Flowable.fromSingle(Single.error(new TestException()).hide()) + .test() + .assertFailure(TestException.class); + } + + @Test + public void cancelComposes() { + SingleSubject ms = SingleSubject.create(); + + TestSubscriber ts = Flowable.fromSingle(ms) + .test(); + + ts.assertEmpty(); + + assertTrue(ms.hasObservers()); + + ts.cancel(); + + assertFalse(ms.hasObservers()); + } + + @Test + public void asyncFusion() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.ASYNC); + + Flowable.fromSingle(Single.just(1)) + .subscribe(ts); + + ts + .assertFuseable() + .assertFusionMode(QueueFuseable.ASYNC) + .assertResult(1); + } + + @Test + public void syncFusionRejected() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + ts.setInitialFusionMode(QueueFuseable.SYNC); + + Flowable.fromSingle(Single.just(1)) + .subscribe(ts); + + ts + .assertFuseable() + .assertFusionMode(QueueFuseable.NONE) + .assertResult(1); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSourceTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSourceTest.java index fefbf1533ec..6506c010ea9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSourceTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSourceTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -137,7 +137,7 @@ public void normalError() { ts.assertError(MissingBackpressureException.class); ts.assertNotComplete(); - Assert.assertEquals("create: could not emit value due to lack of requests", ts.errors().get(0).getMessage()); + Assert.assertEquals("create: " + MissingBackpressureException.DEFAULT_MESSAGE, ts.errors().get(0).getMessage()); } @Test diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSupplierTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSupplierTest.java index 5753e8ff66c..423b1409c1a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSupplierTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableFromSupplierTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.operators.flowable; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGenerateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGenerateTest.java index ecd965a4f89..92746851186 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGenerateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGenerateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -282,4 +282,17 @@ public void accept(Emitter e) throws Exception { .test(1) .assertResult(); } + + @Test + public void onNextAfterOnComplete() { + Flowable.generate(new Consumer>() { + @Override + public void accept(Emitter e) throws Exception { + e.onComplete(); + e.onNext(1); + } + }) + .test() + .assertResult(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupByTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupByTest.java index f20f0ae0c77..d0d7dbea440 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupByTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupByTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,6 +18,7 @@ import static org.mockito.Mockito.*; import java.io.IOException; +import java.time.Duration; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; @@ -34,9 +35,9 @@ import io.reactivex.rxjava3.flowables.GroupedFlowable; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.internal.schedulers.ImmediateThinScheduler; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subjects.PublishSubject; @@ -45,6 +46,15 @@ public class FlowableGroupByTest extends RxJavaTest { + static Function, Flowable> FLATTEN_INTEGER = new Function, Flowable>() { + + @Override + public Flowable apply(GroupedFlowable t) { + return t; + } + + }; + final Function length = new Function() { @Override public Integer apply(String s) { @@ -102,6 +112,7 @@ public void empty() { } @Test + @SuppressUndeliverable public void error() { Flowable sourceStrings = Flowable.just("one", "two", "three", "four", "five", "six"); Flowable errorSource = Flowable.error(new TestException("forced failure")); @@ -1186,6 +1197,7 @@ public void keySelectorThrows() { } @Test + @SuppressUndeliverable public void valueSelectorThrows() { Flowable source = Flowable.just(0, 1, 2, 3, 4, 5, 6); @@ -1241,6 +1253,7 @@ public void accept(GroupedFlowable t1) { } @Test + @SuppressUndeliverable public void error2() { Flowable source = Flowable.concat(Flowable.just(0), Flowable. error(new TestException("Forced failure"))); @@ -1350,15 +1363,6 @@ public String apply(Integer l) { ts.assertNoErrors(); } - static Function, Flowable> FLATTEN_INTEGER = new Function, Flowable>() { - - @Override - public Flowable apply(GroupedFlowable t) { - return t; - } - - }; - @Test public void groupByWithNullKey() { final String[] key = new String[]{"uninitialized"}; @@ -1671,7 +1675,9 @@ public void accept(GroupedFlowable g) { .subscribe(ts2); ts1 - .assertFusionMode(QueueFuseable.ASYNC) + // FIXME fusion mode causes hangs + //.assertFusionMode(QueueFuseable.ASYNC) + .assertFusionMode(QueueFuseable.NONE) .assertValues(2, 3, 4, 5, 6, 7, 8, 9, 10, 11) .assertNoErrors() .assertComplete(); @@ -1683,6 +1689,7 @@ public void accept(GroupedFlowable g) { } @Test + @SuppressUndeliverable public void keySelectorAndDelayError() { Flowable.just(1).concatWith(Flowable.error(new TestException())) .groupBy(Functions.identity(), true) @@ -1697,6 +1704,7 @@ public Flowable apply(GroupedFlowable g) throws Excep } @Test + @SuppressUndeliverable public void keyAndValueSelectorAndDelayError() { Flowable.just(1).concatWith(Flowable.error(new TestException())) .groupBy(Functions.identity(), Functions.identity(), true) @@ -1805,10 +1813,21 @@ public Object apply(Flowable f) throws Exception { @Test public void badRequest() { - TestHelper.assertBadRequestReported(Flowable.just(1) + TestHelper.assertBadRequestReported(Flowable.just(1).hide() .groupBy(Functions.justFunction(1))); } + @Test + public void badRequestInner() { + Flowable.just(1).hide() + .groupBy(Functions.justFunction(1)) + .doOnNext(g -> { + TestHelper.assertBadRequestReported(g); + }) + .test() + .assertNoErrors(); + } + @Test public void doubleOnSubscribe() { TestHelper.checkDoubleOnSubscribeFlowable(new Function, Publisher>>() { @@ -1839,6 +1858,7 @@ public Publisher apply(GroupedFlowable g) throws Excep } @Test + @SuppressUndeliverable public void groupError() { Flowable.just(1).concatWith(Flowable.error(new TestException())) .groupBy(Functions.justFunction(1), true) @@ -1883,6 +1903,39 @@ public Map apply(final Consumer notify) throws Exceptio .assertNoValues() .assertError(ex); } + // ----------------------------------------------------------------------------------------------------------------------- + + private static final Function mod5 = new Function() { + + @Override + public Integer apply(Integer n) throws Exception { + return n % 5; + } + }; + + private static Function, Publisher> addCompletedKey( + final List completed) { + return new Function, Publisher>() { + @Override + public Publisher apply(final GroupedFlowable g) throws Exception { + return g.doOnComplete(new Action() { + @Override + public void run() throws Exception { + completed.add(g.getKey()); + } + }); + } + }; + } + + private static final class TestTicker extends Ticker { + long tick; + + @Override + public long read() { + return tick; + } + } @Test public void mapFactoryExpiryCompletesGroupedFlowable() { @@ -1905,32 +1958,6 @@ public void mapFactoryExpiryCompletesGroupedFlowable() { ts.assertValueCount(3); } - private static final Function mod5 = new Function() { - - @Override - public Integer apply(Integer n) throws Exception { - return n % 5; - } - }; - - @Test - public void mapFactoryWithExpiringGuavaCacheDemonstrationCodeForUseInJavadoc() { - //javadoc will be a version of this using lambdas and without assertions - final List completed = new CopyOnWriteArrayList<>(); - //size should be less than 5 to notice the effect - Function, Map> evictingMapFactory = createEvictingMapFactoryGuava(3); - int numValues = 1000; - TestSubscriber ts = - Flowable.range(1, numValues) - .groupBy(mod5, Functions.identity(), true, 16, evictingMapFactory) - .flatMap(addCompletedKey(completed)) - .test() - .assertComplete(); - ts.assertValueCount(numValues); - //the exact eviction behaviour of the guava cache is not specified so we make some approximate tests - assertTrue(completed.size() > numValues * 0.9); - } - @Test public void mapFactoryEvictionQueueClearedOnErrorCoverageOnly() { Function, Map> evictingMapFactory = createEvictingMapFactorySynchronousOnly(1); @@ -1952,28 +1979,28 @@ public Publisher apply(GroupedFlowable g) throws Exce .assertError(ex); } - private static Function, Publisher> addCompletedKey( - final List completed) { - return new Function, Publisher>() { - @Override - public Publisher apply(final GroupedFlowable g) throws Exception { - return g.doOnComplete(new Action() { - @Override - public void run() throws Exception { - completed.add(g.getKey()); - } - }); - } - }; - } + @Test + public void mapFactoryWithExpiringGuavaCacheDemonstrationCodeForUseInJavadoc() { + //javadoc will be a version of this using lambdas and without assertions + final List completed = new CopyOnWriteArrayList<>(); - private static final class TestTicker extends Ticker { - long tick; + AtomicReference> cacheOut = new AtomicReference<>(); - @Override - public long read() { - return tick; - } + //size should be less than 5 to notice the effect + Function, Map> evictingMapFactory = createEvictingMapFactoryGuava(3, cacheOut); + int numValues = 1000; + TestSubscriber ts = + Flowable.range(1, numValues) + .groupBy(mod5, Functions.identity(), true, 16, evictingMapFactory) + .flatMap(addCompletedKey(completed)) + .test() + .assertComplete() + ; + ts.assertValueCount(numValues); + //the exact eviction behaviour of the guava cache is not specified so we make some approximate tests + assertTrue(completed.size() > numValues * 0.9); + + cacheOut.get().invalidateAll(); } @Test @@ -2066,28 +2093,6 @@ public void run() throws Exception { ), list); } - @Test - public void cancellationOfUpstreamWhenGroupedFlowableCompletes() { - final AtomicBoolean cancelled = new AtomicBoolean(); - Flowable.just(1).repeat().doOnCancel(new Action() { - @Override - public void run() throws Exception { - cancelled.set(true); - } - }) - .groupBy(Functions.identity(), Functions.identity()) // - .flatMap(new Function, Publisher>() { - @Override - public Publisher apply(GroupedFlowable g) throws Exception { - return g.first(0).toFlowable(); - } - }) - .take(4) // - .test() // - .assertComplete(); - assertTrue(cancelled.get()); - } - //not thread safe private static final class SingleThreadEvictingHashMap implements Map { @@ -2185,13 +2190,14 @@ public Set> entrySet() { } } - private static Function, Map> createEvictingMapFactoryGuava(final int maxSize) { + private static Function, Map> createEvictingMapFactoryGuava(final int maxSize, + final AtomicReference> cacheOut) { Function, Map> evictingMapFactory = // new Function, Map>() { @Override public Map apply(final Consumer notify) throws Exception { - return CacheBuilder.newBuilder() // + Cache cache = CacheBuilder.newBuilder() // .maximumSize(maxSize) // .removalListener(new RemovalListener() { @Override @@ -2202,8 +2208,9 @@ public void onRemoval(RemovalNotification notification) { throw new RuntimeException(e); } }}) - . build() - .asMap(); + . build(); + cacheOut.set(cache); + return cache.asMap(); }}; return evictingMapFactory; } @@ -2228,6 +2235,30 @@ public void accept(Object object) { return evictingMapFactory; } + // ----------------------------------------------------------------------------------------------------------------------- + + @Test + public void cancellationOfUpstreamWhenGroupedFlowableCompletes() { + final AtomicBoolean cancelled = new AtomicBoolean(); + Flowable.just(1).repeat().doOnCancel(new Action() { + @Override + public void run() throws Exception { + cancelled.set(true); + } + }) + .groupBy(Functions.identity(), Functions.identity()) // + .flatMap(new Function, Publisher>() { + @Override + public Publisher apply(GroupedFlowable g) throws Exception { + return g.first(0).toFlowable(); + } + }) + .take(4) // + .test() // + .assertComplete(); + assertTrue(cancelled.get()); + } + @Test public void cancelOverFlatmapRace() { for (int i = 0; i < TestHelper.RACE_LONG_LOOPS; i++) { @@ -2444,4 +2475,484 @@ public void accept(Integer v) throws Throwable { .assertNoErrors() .assertComplete(); } + + @Test + public void cancelledGroupResumesRequesting() { + final List> tss = new ArrayList<>(); + final AtomicInteger counter = new AtomicInteger(); + final AtomicBoolean done = new AtomicBoolean(); + Flowable.range(1, 1000) + .doOnNext(new Consumer() { + @Override + public void accept(Integer v) throws Exception { + counter.getAndIncrement(); + } + }) + .groupBy(Functions.justFunction(1)) + .subscribe(new Consumer>() { + @Override + public void accept(GroupedFlowable v) throws Exception { + TestSubscriber ts = TestSubscriber.create(0L); + tss.add(ts); + v.subscribe(ts); + } + }, Functions.emptyConsumer(), new Action() { + @Override + public void run() throws Exception { + done.set(true); + } + }); + + while (!done.get()) { + tss.remove(0).cancel(); + } + + assertEquals(1000, counter.get()); + } + + @Test + public void delayErrorCompleteMoreWorkInGroup() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = pp.groupBy(v -> 1, true) + .flatMap(g -> g.doOnNext(v -> { + if (v == 1) { + pp.onNext(2); + pp.onComplete(); + } + }) + ) + .test() + ; + + pp.onNext(1); + + ts.assertResult(1, 2); + } + + @Test + public void groupSyncFusionRejected() { + Flowable.just(1) + .groupBy(v -> 1) + .doOnNext(g -> { + g.subscribeWith(new TestSubscriberEx().setInitialFusionMode(QueueFuseable.SYNC)) + .assertFuseable() + .assertFusionMode(QueueFuseable.NONE); + }) + .test() + .assertComplete(); + } + + @Test + public void subscribeAbandonRace() throws Throwable { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = TestSubscriber.create(); + + CountDownLatch cdl = new CountDownLatch(1); + + pp.groupBy(v -> 1) + .doOnNext(g -> { + TestHelper.raceOther(() -> { + g.subscribe(ts); + }, cdl); + }) + .test(); + + pp.onNext(1); + + cdl.await(); + + ts.assertValueCount(1); + } + } + + @Test + public void issue6974() { + + FlowableTransformer operation = + source -> source.publish(shared -> + shared + .firstElement() + .flatMapPublisher(firstElement -> + Flowable.just(firstElement).concatWith(shared) + ) + ); + + issue6974Run(20, 500_000, 20 - 1, 20 * 2, operation, false); + + issue6974Run(20, 500_000, 20, 20 * 2, operation, false); + } + + static void issue6974Run(int groups, int iterations, int sizeCap, int flatMapConcurrency, + FlowableTransformer operation, boolean notifyOnExplicitRevoke) { + TestSubscriber test = Flowable + .range(1, groups) + .repeat(iterations / groups) + .groupBy(i -> i, i -> i, false, 128, sizeCap(sizeCap, notifyOnExplicitRevoke)) + .flatMap(gf -> gf.compose(operation), flatMapConcurrency) + .test(); + test.awaitDone(5, TimeUnit.SECONDS); + test.assertValueCount(iterations); + } + + static Function, Map> sizeCap(int maxCapacity, boolean notifyOnExplicit) { + return itemEvictConsumer -> + CacheBuilder + .newBuilder() + .maximumSize(maxCapacity) + .removalListener(notification -> { + if (notification.getCause() != RemovalCause.EXPLICIT || notifyOnExplicit) { + try { + itemEvictConsumer.accept(notification.getValue()); + } catch (Throwable throwable) { + throw new RuntimeException(throwable); + } + } + }) + .build().asMap(); + } + + static void issue6974RunPart2(int groupByBufferSize, int flatMapMaxConcurrency, int groups, + boolean notifyOnExplicitEviction) { + TestSubscriber ts = Flowable + .range(1, 500_000) + .map(i -> i % groups) + .groupBy(i -> i, i -> i, false, groupByBufferSize, + // set cap too high + sizeCap(groups * 100, notifyOnExplicitEviction)) + .flatMap(gf -> gf + .take(10, TimeUnit.MILLISECONDS) + , flatMapMaxConcurrency) + .test(); + + ts + .awaitDone(5, TimeUnit.SECONDS) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void issue6974Part2Case1() { + final int groups = 20; + + // Not completed (Timed out), buffer is too small + int groupByBufferSize = groups * 2; + int flatMapMaxConcurrency = 2 * groups; + boolean notifyOnExplicitEviction = false; + issue6974RunPart2(groupByBufferSize, flatMapMaxConcurrency, groups, notifyOnExplicitEviction); + } + + @Test + public void issue6974Part2Case2() { + final int groups = 20; + + // Timeout... explicit eviction notification makes difference + int groupByBufferSize = groups * 30; + int flatMapMaxConcurrency = 2 * groups; + boolean notifyOnExplicitEviction = true; + issue6974RunPart2(groupByBufferSize, flatMapMaxConcurrency, groups, notifyOnExplicitEviction); + } + + /* + * Disabled: Takes very long. Run it locally only. + @Test + public void issue6974Part2Case2Loop() { + for (int i = 0; i < 1000; i++) { + issue6974Part2Case2(); + } + } + */ + + static void issue6974RunPart2NoEvict(int groupByBufferSize, int flatMapMaxConcurrency, int groups, + boolean notifyOnExplicitEviction) { + + Flowable + .range(1, 500_000) + .map(i -> i % groups) + .groupBy(i -> i) + .flatMap(gf -> gf + .take(10, TimeUnit.MILLISECONDS) + , flatMapMaxConcurrency) + .subscribeWith(new TestSubscriberEx<>()) + .awaitDone(5, TimeUnit.SECONDS) + .assertTerminated(); // MBE is possible if the async group closing is slow + } + + @Test + public void issue6974Part2Case1NoEvict() { + final int groups = 20; + + // Not completed (Timed out), buffer is too small + int groupByBufferSize = groups * 2; + int flatMapMaxConcurrency = 2 * groups; + boolean notifyOnExplicitEviction = false; + issue6974RunPart2NoEvict(groupByBufferSize, flatMapMaxConcurrency, groups, notifyOnExplicitEviction); + } + + /* + * Disabled: Takes very long. Run it locally only. + @Test + public void issue6974Part2Case1NoEvictLoop() { + for (int i = 0; i < 1000; i++) { + issue6974Part2Case1NoEvict(); + } + } + */ + + @Test + public void issue6974Part2Case1ObserveOn() { + final int groups = 20; + + // Not completed (Timed out), buffer is too small + int groupByBufferSize = groups * 2; + int flatMapMaxConcurrency = 2 * groups; + boolean notifyOnExplicitEviction = false; + + Flowable + .range(1, 500_000) + .map(i -> i % groups) + .doOnCancel(() -> { + System.out.println("Cancelling upstream"); + }) + .groupBy(i -> i, i -> i, false, groupByBufferSize, + sizeCap(groups * 2, notifyOnExplicitEviction)) + .flatMap(gf -> gf + .observeOn(Schedulers.computation()) + // .take(10) + .take(10, TimeUnit.MILLISECONDS) + , flatMapMaxConcurrency) + .subscribeWith(new TestSubscriberEx<>()) + .awaitDone(5, TimeUnit.SECONDS) + .assertTerminated(); // MBE is possible if the async group closing is slow + } + + @Test + public void issue6974Part2Case1ObserveOnHide() { + final int groups = 20; + + // Not completed (Timed out), buffer is too small + int groupByBufferSize = groups * 2; + int flatMapMaxConcurrency = 2 * groups; + boolean notifyOnExplicitEviction = false; + + Flowable + .range(1, 500_000) + .map(i -> i % groups) + .doOnCancel(() -> System.out.println("Cancelling upstream")) + .groupBy(i -> i, i -> i, false, groupByBufferSize, + sizeCap(groups * 2, notifyOnExplicitEviction)) + .flatMap(gf -> gf + .hide() + .observeOn(Schedulers.computation()) + // .take(10) + .take(10, TimeUnit.MILLISECONDS) + , flatMapMaxConcurrency) + .subscribeWith(new TestSubscriberEx<>()) + .awaitDone(5, TimeUnit.SECONDS) + .assertTerminated(); // MBE is possible if the async group closing is slow + } + + @Test + public void issue6974Part2Case1ObserveOnNoCap() { + final int groups = 20; + + // Not completed (Timed out), buffer is too small + int flatMapMaxConcurrency = 1_000_000; + + Flowable + .range(1, 500_000) + .map(i -> i % groups) + .doOnRequest(v -> { + System.out.println("Source: " + v); + }) + .groupBy(i -> i) + .flatMap(gf -> gf + .observeOn(Schedulers.computation()) + // .take(10) + .take(10, TimeUnit.MILLISECONDS) + , flatMapMaxConcurrency) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void issue6974Part2Case1ObserveOnNoCapHide() { + final int groups = 20; + + // Not completed (Timed out), buffer is too small + int flatMapMaxConcurrency = 1_000_000; + + Flowable + .range(1, 500_000) + .map(i -> i % groups) + .doOnRequest(v -> { + System.out.println("Source: " + v); + }) + .groupBy(i -> i) + .flatMap(gf -> gf + .hide() + .observeOn(Schedulers.computation()) + // .take(10) + .take(10, TimeUnit.MILLISECONDS) + , flatMapMaxConcurrency) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertNoErrors() + .assertComplete(); + } + + /* + * Disabled: Takes very long. Run it locally only. + @Test + public void issue6974Part2Case1ObserveOnNoCapHideLoop() { + for (int i = 0; i < 100; i++) { + issue6974Part2Case1ObserveOnNoCapHide(); + } + } + */ + + @Test + public void issue6974Part2Case1ObserveOnConditional() { + final int groups = 20; + + // Not completed (Timed out), buffer is too small + int groupByBufferSize = groups * 2; + int flatMapMaxConcurrency = 2 * groups; + boolean notifyOnExplicitEviction = false; + + Flowable + .range(1, 500_000) + .map(i -> i % groups) + .doOnCancel(() -> System.out.println("Cancelling upstream")) + .groupBy(i -> i, i -> i, false, groupByBufferSize, + sizeCap(groups * 2, notifyOnExplicitEviction)) + .flatMap(gf -> gf + .observeOn(Schedulers.computation()) + .filter(v -> true) + // .take(10) + .take(10, TimeUnit.MILLISECONDS) + , flatMapMaxConcurrency) + .subscribeWith(new TestSubscriberEx<>()) + .awaitDone(5, TimeUnit.SECONDS) + .assertTerminated(); // MBE is possible if the async group closing is slow + } + + @Test + public void issue6974Part2Case1ObserveOnConditionalHide() { + final int groups = 20; + + // Not completed (Timed out), buffer is too small + int groupByBufferSize = groups * 2; + int flatMapMaxConcurrency = 2 * groups; + boolean notifyOnExplicitEviction = false; + + Flowable + .range(1, 500_000) + .map(i -> i % groups) + .doOnCancel(() -> System.out.println("Cancelling upstream")) + .groupBy(i -> i, i -> i, false, groupByBufferSize, + sizeCap(groups * 2, notifyOnExplicitEviction)) + .flatMap(gf -> gf + .hide() + .observeOn(Schedulers.computation()) + .filter(v -> true) + // .take(10) + .take(10, TimeUnit.MILLISECONDS) + , flatMapMaxConcurrency) + .subscribeWith(new TestSubscriberEx<>()) + .awaitDone(5, TimeUnit.SECONDS) + .assertTerminated(); // MBE is possible if the async group closing is slow + } + + /* + * Disabled: Takes very long. Run it locally only. + @Test + public void issue6974Part2Case1ObserveOnHideLoop() { + for (int i = 0; i < 100; i++) { + issue6974Part2Case1ObserveOnHide(); + } + } + */ + + static Function, ConcurrentMap> ttlCapGuava(Duration ttl) { + return itemEvictConsumer -> + CacheBuilder + .newBuilder() + .expireAfterWrite(ttl) + .removalListener(n -> { + if (n.getCause() != com.google.common.cache.RemovalCause.EXPLICIT) { + try { + itemEvictConsumer.accept(n.getValue()); + } catch (Throwable throwable) { + throw new RuntimeException(throwable); + } + } + }).build().asMap(); + } + + @Test + public void issue6982Case1() { + final int groups = 20; + + int groupByBufferSize = 2; + int flatMapMaxConcurrency = 200 * groups; + + // ~50% of executions - Not completed (latch = 1, values = 500000, errors = 0, completions = 0, timeout!, + // disposed!) + + Flowable + .range(1, 500_000) + .map(i -> i % groups) + .groupBy(i -> i, i -> i, false, groupByBufferSize, ttlCapGuava(Duration.ofMillis(10))) + .flatMap(gf -> gf.observeOn(Schedulers.computation()), flatMapMaxConcurrency) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertNoErrors() + .assertComplete(); + } + + /* + * Disabled: Takes very long. Run it locally only. + @Test + public void issue6982Case1Loop() { + for (int i = 0; i < 200; i++) { + System.out.println("issue6982Case1Loop " + i); + issue6982Case1(); + } + } + */ + + @Test + public void issue6982Case2() { + final int groups = 20; + + int groupByBufferSize = groups * 30; + int flatMapMaxConcurrency = groups * 500; + // Always : Not completed (latch = 1, values = 14100, errors = 0, completions = 0, timeout!, disposed!) + + Flowable + .range(1, 500_000) + .map(i -> i % groups) + .groupBy(i -> i, i -> i, false, groupByBufferSize, ttlCapGuava(Duration.ofMillis(10))) + .flatMap(gf -> gf.observeOn(Schedulers.computation()), flatMapMaxConcurrency) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertNoErrors() + .assertComplete(); + } + + /* + * Disabled: Takes very long. Run it locally only. + @Test + public void issue6982Case2Loop() { + for (int i = 0; i < 200; i++) { + System.out.println("issue6982Case2Loop " + i); + issue6982Case2(); + } + } + */ } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupJoinTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupJoinTest.java index bed06869235..fe83ad9fffe 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupJoinTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableGroupJoinTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import static org.junit.Assert.*; @@ -31,7 +29,7 @@ import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.internal.operators.flowable.FlowableGroupJoin.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; @@ -79,7 +77,7 @@ public Integer apply(Integer rightValue) throws Throwable { @Before public void before() { - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this); } @Test @@ -732,4 +730,55 @@ public void leftRightEndState() { verify(js).innerClose(false, o); } + + @Test + public void disposeAfterOnNext() { + PublishProcessor pp1 = PublishProcessor.create(); + PublishProcessor pp2 = PublishProcessor.create(); + + TestSubscriber ts = new TestSubscriber<>(); + + pp1.groupJoin(pp2, v -> Flowable.never(), v -> Flowable.never(), (a, b) -> a) + .doOnNext(v -> { + ts.cancel(); + }) + .subscribe(ts); + + pp2.onNext(1); + pp1.onNext(1); + } + + @Test + public void completeWithMoreWork() { + PublishProcessor pp1 = PublishProcessor.create(); + PublishProcessor pp2 = PublishProcessor.create(); + + TestSubscriber ts = new TestSubscriber<>(); + + pp1.groupJoin(pp2, v -> Flowable.never(), v -> Flowable.never(), (a, b) -> a) + .doOnNext(v -> { + if (v == 1) { + pp2.onNext(2); + pp1.onComplete(); + pp2.onComplete(); + } + }) + .subscribe(ts); + + pp2.onNext(1); + pp1.onNext(1); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().groupJoin(Flowable.never(), v -> Flowable.never(), v -> Flowable.never(), (a, b) -> a)); + } + + @Test + public void missingBackpressure() { + Flowable.just(1) + .groupJoin(Flowable.never(), v -> BehaviorProcessor.createDefault(1), v -> Flowable.never(), (a, b) -> a) + .test(0) + .assertFailure(MissingBackpressureException.class); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableHideTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableHideTest.java index c2162b2872c..f95775ebda7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableHideTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableHideTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIgnoreElementsTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIgnoreElementsTest.java index 2558b4a4339..dfc0e116808 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIgnoreElementsTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIgnoreElementsTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,8 +23,9 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.observers.DisposableCompletableObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.subscribers.*; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableInternalHelperTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableInternalHelperTest.java index e570842c981..1549f01d636 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableInternalHelperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableInternalHelperTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import org.junit.Test; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIntervalRangeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIntervalRangeTest.java index 46cf13229b9..f8bc3355e9f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIntervalRangeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIntervalRangeTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.operators.flowable; @@ -118,4 +115,12 @@ public void cancel() { .test() .assertResult(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L); } + + @Test + public void takeSameAsRange() { + Flowable.intervalRange(0, 2, 1, 1, TimeUnit.MILLISECONDS, Schedulers.trampoline()) + .take(2) + .test() + .assertResult(0L, 1L); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIntervalTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIntervalTest.java index 68b8bd59fd8..7fde08d47fd 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIntervalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableIntervalTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableJoinTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableJoinTest.java index 7c33df579cf..fe28a933204 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableJoinTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableJoinTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import static org.mockito.ArgumentMatchers.any; @@ -55,7 +53,7 @@ public Flowable apply(Integer t1) { @Before public void before() { - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this); } @Test @@ -487,4 +485,35 @@ public Object apply(Integer a, Integer b) throws Exception { ts.assertFailure(MissingBackpressureException.class); } + + @Test + public void badRequest() { + PublishProcessor pp1 = PublishProcessor.create(); + PublishProcessor pp2 = PublishProcessor.create(); + + TestHelper.assertBadRequestReported(pp1.join(pp2, Functions.justFunction(Flowable.never()), Functions.justFunction(Flowable.never()), (a, b) -> a + b)); + } + + @Test + public void bothTerminateWithWorkRemaining() { + PublishProcessor pp1 = PublishProcessor.create(); + PublishProcessor pp2 = PublishProcessor.create(); + + TestSubscriber ts = pp1.join( + pp2, + v -> Flowable.never(), + v -> Flowable.never(), + (a, b) -> a + b) + .doOnNext(v -> { + pp1.onComplete(); + pp2.onNext(2); + pp2.onComplete(); + }) + .test(); + + pp1.onNext(0); + pp2.onNext(1); + + ts.assertComplete(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLastTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLastTest.java index 1897d236d6f..3164802ab6d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLastTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLastTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLiftTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLiftTest.java index c208b8370b2..68227e8dfc6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLiftTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableLiftTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapNotificationTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapNotificationTest.java index 0deec9376b7..905cda55481 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapNotificationTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapNotificationTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapTest.java index 1c0e6c58a34..3d77fe5d46e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,8 +27,10 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.*; +import io.reactivex.rxjava3.internal.schedulers.ImmediateThinScheduler; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.Schedulers; @@ -617,4 +619,19 @@ public Object apply(Flowable f) throws Exception { }, false, 1, 1, 1); } + @Test + public void conditionalFusionNoNPE() { + TestSubscriberEx ts = new TestSubscriberEx<>() + .setInitialFusionMode(QueueFuseable.ANY); + + Flowable.empty() + .observeOn(ImmediateThinScheduler.INSTANCE) + .filter(v -> true) + .map(v -> v) + .filter(v -> true) + .subscribe(ts) + ; + + ts.assertResult(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMaterializeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMaterializeTest.java index 1d798e62723..0f9c3df225d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMaterializeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMaterializeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeDelayErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeDelayErrorTest.java index 64a2206e846..1959921168e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeDelayErrorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeDelayErrorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeMaxConcurrentTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeMaxConcurrentTest.java index b2582430bb1..25b9cd825a1 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeMaxConcurrentTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeMaxConcurrentTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeTest.java index 3a1d65fc33f..57b7a4a6670 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -204,7 +204,7 @@ public void mergeArrayWithThreading() { TestSubscriber ts = new TestSubscriber<>(stringSubscriber); m.subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); verify(stringSubscriber, never()).onError(any(Throwable.class)); @@ -598,7 +598,7 @@ public void run() { TestSubscriber ts = new TestSubscriber<>(); merge.subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertComplete(); List onNextEvents = ts.values(); assertEquals(300, onNextEvents.size()); @@ -645,7 +645,7 @@ public void run() { TestSubscriber ts = new TestSubscriber<>(); merge.subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); ts.assertComplete(); List onNextEvents = ts.values(); @@ -706,7 +706,7 @@ public void onNext(Integer t) { }; Flowable.merge(f1.take(Flowable.bufferSize() * 2), Flowable.just(-99)).subscribe(testSubscriber); - testSubscriber.awaitDone(5, TimeUnit.SECONDS); + testSubscriber.awaitDone(10, TimeUnit.SECONDS); List onNextEvents = testSubscriber.values(); @@ -752,7 +752,7 @@ public void onNext(Integer t) { }; Flowable.merge(f1.take(Flowable.bufferSize() * 2), f2.take(Flowable.bufferSize() * 2)).observeOn(Schedulers.computation()).subscribe(testSubscriber); - testSubscriber.awaitDone(5, TimeUnit.SECONDS); + testSubscriber.awaitDone(10, TimeUnit.SECONDS); if (testSubscriber.errors().size() > 0) { testSubscriber.errors().get(0).printStackTrace(); } @@ -795,7 +795,7 @@ public void onNext(Integer t) { }; Flowable.merge(f1).observeOn(Schedulers.computation()).take(Flowable.bufferSize() * 2).subscribe(testSubscriber); - testSubscriber.awaitDone(5, TimeUnit.SECONDS); + testSubscriber.awaitDone(10, TimeUnit.SECONDS); if (testSubscriber.errors().size() > 0) { testSubscriber.errors().get(0).printStackTrace(); } @@ -850,7 +850,7 @@ public void onNext(Integer t) { }; Flowable.merge(f1).observeOn(Schedulers.computation()).take(Flowable.bufferSize() * 2).subscribe(testSubscriber); - testSubscriber.awaitDone(5, TimeUnit.SECONDS); + testSubscriber.awaitDone(10, TimeUnit.SECONDS); if (testSubscriber.errors().size() > 0) { testSubscriber.errors().get(0).printStackTrace(); } @@ -868,7 +868,7 @@ public void onNext(Integer t) { public void merge1AsyncStreamOf1() { TestSubscriber ts = new TestSubscriber<>(); mergeNAsyncStreamsOfN(1, 1).subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); assertEquals(1, ts.values().size()); } @@ -877,7 +877,7 @@ public void merge1AsyncStreamOf1() { public void merge1AsyncStreamOf1000() { TestSubscriber ts = new TestSubscriber<>(); mergeNAsyncStreamsOfN(1, 1000).subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); assertEquals(1000, ts.values().size()); } @@ -886,7 +886,7 @@ public void merge1AsyncStreamOf1000() { public void merge10AsyncStreamOf1000() { TestSubscriber ts = new TestSubscriber<>(); mergeNAsyncStreamsOfN(10, 1000).subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); assertEquals(10000, ts.values().size()); } @@ -895,7 +895,7 @@ public void merge10AsyncStreamOf1000() { public void merge1000AsyncStreamOf1000() { TestSubscriber ts = new TestSubscriber<>(); mergeNAsyncStreamsOfN(1000, 1000).subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); assertEquals(1000000, ts.values().size()); } @@ -904,7 +904,7 @@ public void merge1000AsyncStreamOf1000() { public void merge2000AsyncStreamOf100() { TestSubscriber ts = new TestSubscriber<>(); mergeNAsyncStreamsOfN(2000, 100).subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); assertEquals(200000, ts.values().size()); } @@ -913,7 +913,7 @@ public void merge2000AsyncStreamOf100() { public void merge100AsyncStreamOf1() { TestSubscriber ts = new TestSubscriber<>(); mergeNAsyncStreamsOfN(100, 1).subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); assertEquals(100, ts.values().size()); } @@ -935,7 +935,7 @@ public Flowable apply(Integer i) { public void merge1SyncStreamOf1() { TestSubscriber ts = new TestSubscriber<>(); mergeNSyncStreamsOfN(1, 1).subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); assertEquals(1, ts.values().size()); } @@ -944,7 +944,7 @@ public void merge1SyncStreamOf1() { public void merge1SyncStreamOf1000000() { TestSubscriber ts = new TestSubscriber<>(); mergeNSyncStreamsOfN(1, 1000000).subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); assertEquals(1000000, ts.values().size()); } @@ -953,7 +953,7 @@ public void merge1SyncStreamOf1000000() { public void merge1000SyncStreamOf1000() { TestSubscriber ts = new TestSubscriber<>(); mergeNSyncStreamsOfN(1000, 1000).subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); assertEquals(1000000, ts.values().size()); } @@ -962,7 +962,7 @@ public void merge1000SyncStreamOf1000() { public void merge10000SyncStreamOf10() { TestSubscriber ts = new TestSubscriber<>(); mergeNSyncStreamsOfN(10000, 10).subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); assertEquals(100000, ts.values().size()); } @@ -971,7 +971,7 @@ public void merge10000SyncStreamOf10() { public void merge1000000SyncStreamOf1() { TestSubscriber ts = new TestSubscriber<>(); mergeNSyncStreamsOfN(1000000, 1).subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); assertEquals(1000000, ts.values().size()); } @@ -1043,7 +1043,7 @@ public void subscribe(Subscriber s) { }); Flowable.merge(os).subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(10, TimeUnit.SECONDS); ts.assertNoErrors(); assertEquals(10000, ts.values().size()); } @@ -1196,7 +1196,7 @@ public void run() { latch.countDown(); } }).subscribe(); - boolean a = latch.await(2, TimeUnit.SECONDS); + boolean a = latch.await(10, TimeUnit.SECONDS); if (!a) { for (String s : messages) { System.out.println("DEBUG => " + s); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithCompletableTest.java index c074796be6d..8eab622ccfd 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithMaybeTest.java index e5ef48a4267..aeef5bb09bf 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithMaybeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithMaybeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -28,7 +28,7 @@ import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; -import io.reactivex.rxjava3.subjects.MaybeSubject; +import io.reactivex.rxjava3.subjects.*; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.TestHelper; @@ -448,4 +448,22 @@ public Flowable apply(Flowable upstream) { } }); } + + @Test + public void drainMoreWorkBeforeCancel() { + MaybeSubject ms = MaybeSubject.create(); + + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.range(1, 5).mergeWith(ms) + .doOnNext(v -> { + if (v == 1) { + ms.onSuccess(6); + ts.cancel(); + } + }) + .subscribe(ts); + + ts.assertValuesOnly(1); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithSingleTest.java index a48ee16fef9..23612f57546 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableMergeWithSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -444,4 +444,22 @@ public Flowable apply(Flowable upstream) { } }); } + + @Test + public void drainMoreWorkBeforeCancel() { + SingleSubject ss = SingleSubject.create(); + + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.range(1, 5).mergeWith(ss) + .doOnNext(v -> { + if (v == 1) { + ss.onSuccess(6); + ts.cancel(); + } + }) + .subscribe(ts); + + ts.assertValuesOnly(1); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOnTest.java index 7fbf19fa606..e4e3d6f3fe8 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableObserveOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -31,11 +31,13 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.operators.flowable.FlowableObserveOn.BaseObserveOnSubscriber; import io.reactivex.rxjava3.internal.schedulers.ImmediateThinScheduler; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.*; @@ -577,13 +579,13 @@ public void onNext(Integer t) { assertEquals(1, errors.size()); System.out.println("Errors: " + errors); Throwable t = errors.get(0); - if (t instanceof MissingBackpressureException) { + if (t instanceof QueueOverflowException) { // success, we expect this } else { - if (t.getCause() instanceof MissingBackpressureException) { + if (t.getCause() instanceof QueueOverflowException) { // this is also okay } else { - fail("Expecting MissingBackpressureException"); + fail("Expecting QueueOverflowException"); } } } @@ -1154,6 +1156,16 @@ public Flowable apply(Flowable f) throws Exception { }); } + @Test + public void doubleOnSubscribeConditional() { + TestHelper.checkDoubleOnSubscribeFlowable(new Function, Flowable>() { + @Override + public Flowable apply(Flowable f) throws Exception { + return f.observeOn(new TestScheduler()).compose(TestHelper.conditional()); + } + }); + } + @Test public void badSource() { List errors = TestHelper.trackPluginErrors(); @@ -1988,4 +2000,120 @@ public void fusedParallelProcessing() { .assertComplete() .assertNoErrors(); } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().observeOn(ImmediateThinScheduler.INSTANCE)); + } + + @Test + public void syncFusedCancelAfterPoll() { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.just(1) + .map(v -> { + ts.cancel(); + return v + 1; + }) + .compose(TestHelper.flowableStripBoundary()) + .observeOn(ImmediateThinScheduler.INSTANCE) + .subscribe(ts); + + ts.assertEmpty(); + } + + @Test + public void syncFusedCancelAfterPollConditional() { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.just(1) + .map(v -> { + ts.cancel(); + return v + 1; + }) + .compose(TestHelper.flowableStripBoundary()) + .observeOn(ImmediateThinScheduler.INSTANCE) + .compose(TestHelper.conditional()) + .subscribe(ts); + + ts.assertEmpty(); + } + + @Test + public void backFusedMoreWork() { + final TestSubscriberEx ts = new TestSubscriberEx().setInitialFusionMode(QueueFuseable.ANY); + + PublishProcessor pp = PublishProcessor.create(); + + pp.observeOn(ImmediateThinScheduler.INSTANCE) + .doOnNext(v -> { + if (v == 1) { + pp.onNext(2); + } + }) + .subscribe(ts); + + pp.onNext(1); + + ts.assertValuesOnly(1, 2); + } + + @Test + public void moreWorkInRunAsync() { + final TestSubscriberEx ts = new TestSubscriberEx<>(); + + PublishProcessor pp = PublishProcessor.create(); + + pp.observeOn(ImmediateThinScheduler.INSTANCE) + .doOnNext(v -> { + if (v == 1) { + pp.onNext(2); + } + }) + .subscribe(ts); + + pp.onNext(1); + + ts.assertValuesOnly(1, 2); + } + + @Test + public void backFusedConditionalMoreWork() { + final TestSubscriberEx ts = new TestSubscriberEx().setInitialFusionMode(QueueFuseable.ANY); + + PublishProcessor pp = PublishProcessor.create(); + + pp.observeOn(ImmediateThinScheduler.INSTANCE) + .doOnNext(v -> { + if (v == 1) { + pp.onNext(2); + } + }) + .compose(TestHelper.conditional()) + .subscribe(ts); + + pp.onNext(1); + + ts.assertValuesOnly(1, 2); + } + + @Test + public void conditionalMoreWorkInRunAsync() { + final TestSubscriberEx ts = new TestSubscriberEx<>(); + + PublishProcessor pp = PublishProcessor.create(); + + pp.observeOn(ImmediateThinScheduler.INSTANCE) + .doOnNext(v -> { + if (v == 1) { + pp.onNext(2); + } + }) + .compose(TestHelper.conditional()) + .subscribe(ts); + + pp.onNext(1); + + ts.assertValuesOnly(1, 2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBufferStrategyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBufferStrategyTest.java index 327078ad602..217162c206c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBufferStrategyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBufferStrategyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,7 +15,9 @@ import static io.reactivex.rxjava3.core.BackpressureOverflowStrategy.*; import static io.reactivex.rxjava3.internal.functions.Functions.EMPTY_ACTION; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -28,8 +30,9 @@ import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.subscribers.*; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class FlowableOnBackpressureBufferStrategyTest extends RxJavaTest { @@ -206,4 +209,117 @@ public void justTake() { .test() .assertResult(1); } + + @Test + public void overflowNullAction() { + Flowable.range(1, 5) + .onBackpressureBuffer(1, null, BackpressureOverflowStrategy.DROP_OLDEST) + .test(0L) + .assertEmpty(); + } + + @Test + public void cancelOnDrain() { + Flowable.range(1, 5) + .onBackpressureBuffer(10, null, BackpressureOverflowStrategy.DROP_OLDEST) + .takeUntil(v -> true) + .test(0L) + .assertEmpty() + .requestMore(10) + .assertResult(1); + } + + @Test + public void onDroppedNormalDropOldest() throws Throwable { + PublishProcessor pp = PublishProcessor.create(); + + @SuppressWarnings("unchecked") + Consumer onDropped = mock(Consumer.class); + + TestSubscriber ts = pp.onBackpressureBuffer(1, null, BackpressureOverflowStrategy.DROP_OLDEST, onDropped) + .test(0L); + + ts.assertEmpty(); + + pp.onNext(1); + + ts.assertEmpty(); + verify(onDropped, never()).accept(any()); + + pp.onNext(2); + + ts.assertEmpty(); + + verify(onDropped).accept(1); + } + + @Test + public void onDroppedNormalDropLatest() throws Throwable { + PublishProcessor pp = PublishProcessor.create(); + + @SuppressWarnings("unchecked") + Consumer onDropped = mock(Consumer.class); + + TestSubscriber ts = pp.onBackpressureBuffer(2, null, BackpressureOverflowStrategy.DROP_LATEST, onDropped) + .test(0L); + + ts.assertEmpty(); + + pp.onNext(1); + + pp.onNext(2); + + ts.assertEmpty(); + verify(onDropped, never()).accept(any()); + + pp.onNext(3); + + ts.assertEmpty(); + + verify(onDropped).accept(2); + } + + @Test + public void onDroppedNormalError() throws Throwable { + PublishProcessor pp = PublishProcessor.create(); + + @SuppressWarnings("unchecked") + Consumer onDropped = mock(Consumer.class); + + TestSubscriber ts = pp.onBackpressureBuffer(1, null, BackpressureOverflowStrategy.ERROR, onDropped) + .test(0L); + + ts.assertEmpty(); + + pp.onNext(1); + + ts.assertEmpty(); + verify(onDropped, never()).accept(any()); + + pp.onNext(2); + + ts.assertFailure(MissingBackpressureException.class); + + verify(onDropped).accept(2); + } + + @Test + public void onDroppedCrash() throws Throwable { + PublishProcessor pp = PublishProcessor.create(); + + Consumer onDropped = v -> { throw new TestException(); }; + + TestSubscriberEx ts = pp.onBackpressureBuffer(1, null, BackpressureOverflowStrategy.DROP_OLDEST, onDropped) + .subscribeWith(new TestSubscriberEx(0L)); + + ts.assertEmpty(); + + pp.onNext(1); + + ts.assertEmpty(); + + pp.onNext(2); + + ts.assertFailure(TestException.class); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBufferTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBufferTest.java index a877b1a3902..657ce36f1b3 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBufferTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureBufferTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,6 +14,8 @@ package io.reactivex.rxjava3.internal.operators.flowable; import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; import java.util.List; import java.util.concurrent.*; @@ -26,9 +28,9 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.schedulers.Schedulers; @@ -215,14 +217,6 @@ public void fixBackpressureBufferZeroCapacity2() throws InterruptedException { Flowable.empty().onBackpressureBuffer(0); } - @Test(expected = NullPointerException.class) - public void fixBackpressureBufferNullStrategy() throws InterruptedException { - Flowable.empty().onBackpressureBuffer(10, new Action() { - @Override - public void run() { } - }, null); - } - @Test public void noDelayError() { @@ -348,4 +342,60 @@ public void fusedNoConcurrentCleanDueToCancel() { } } } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.onBackpressureBuffer()); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().onBackpressureBuffer()); + } + + @Test + public void onDroppedNormal() throws Throwable { + PublishProcessor pp = PublishProcessor.create(); + + @SuppressWarnings("unchecked") + Consumer onDropped = mock(Consumer.class); + + TestSubscriber ts = pp.onBackpressureBuffer(1, false, false, () -> { }, onDropped) + .test(0L); + + ts.assertEmpty(); + + pp.onNext(1); + + ts.assertEmpty(); + verify(onDropped, never()).accept(any()); + + pp.onNext(2); + + ts.assertFailure(MissingBackpressureException.class); + + verify(onDropped).accept(2); + } + + @Test + public void onDroppedCrash() throws Throwable { + PublishProcessor pp = PublishProcessor.create(); + + Consumer onDropped = v -> { throw new TestException(); }; + + TestSubscriberEx ts = pp.onBackpressureBuffer(1, false, false, () -> { }, onDropped) + .subscribeWith(new TestSubscriberEx(0L)); + + ts.assertEmpty(); + + pp.onNext(1); + + ts.assertEmpty(); + + pp.onNext(2); + + ts.assertFailure(MissingBackpressureException.class); + + assertTrue(ts.errors().get(0).getCause() instanceof TestException); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureDropTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureDropTest.java index 811e27f7669..0dfec9422ce 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureDropTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureDropTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureErrorTest.java index 76fad7bf491..2693bf30145 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureErrorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureErrorTest.java @@ -1,11 +1,11 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. - *

+ * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at - *

+ * * http://www.apache.org/licenses/LICENSE-2.0 - *

+ * * Unless required by applicable law or agreed to in writing, software distributed under the License is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. @@ -13,11 +13,16 @@ package io.reactivex.rxjava3.internal.operators.flowable; +import static org.junit.Assert.*; + import org.junit.Test; import org.reactivestreams.Publisher; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.MissingBackpressureException; import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.subjects.PublishSubject; +import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.TestHelper; public class FlowableOnBackpressureErrorTest extends RxJavaTest { @@ -51,4 +56,20 @@ public Object apply(Flowable f) throws Exception { } }, false, 1, 1, 1); } + + @Test + public void overflowCancels() { + PublishSubject ps = PublishSubject.create(); + + TestSubscriber ts = ps.toFlowable(BackpressureStrategy.ERROR) + .test(0L); + + assertTrue(ps.hasObservers()); + + ps.onNext(1); + + assertFalse(ps.hasObservers()); + + ts.assertFailure(MissingBackpressureException.class); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureLatestTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureLatestTest.java index 438ebb1415e..f0d50994ed7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureLatestTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureLatestTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,6 +17,7 @@ import java.util.concurrent.TimeUnit; import org.junit.*; +import org.mockito.InOrder; import org.reactivestreams.Publisher; import io.reactivex.rxjava3.core.*; @@ -27,6 +28,8 @@ import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; +import static org.mockito.Mockito.inOrder; + public class FlowableOnBackpressureLatestTest extends RxJavaTest { @Test public void simple() { @@ -62,6 +65,68 @@ public void simpleBackpressure() { ts.assertNotComplete(); } + @Test + public void simpleBackpressureWithOnDroppedCallback() { + PublishProcessor source = PublishProcessor.create(); + TestSubscriberEx ts = new TestSubscriberEx<>(0L); + + Observer dropCallbackObserver = TestHelper.mockObserver(); + + source.onBackpressureLatest(dropCallbackObserver::onNext) + .subscribe(ts); + + ts.assertNoValues(); + + source.onNext(1); + source.onNext(2); + source.onNext(3); + + ts.request(1); + + ts.assertValues(3); + + source.onNext(4); + source.onNext(5); + + ts.request(2); + + ts.assertValues(3,5); + + InOrder dropCallbackOrder = inOrder(dropCallbackObserver); + dropCallbackOrder.verify(dropCallbackObserver).onNext(1); + dropCallbackOrder.verify(dropCallbackObserver).onNext(2); + dropCallbackOrder.verify(dropCallbackObserver).onNext(4); + dropCallbackOrder.verifyNoMoreInteractions(); + } + + @Test + public void simpleBackpressureWithOnDroppedCallbackEx() { + PublishProcessor source = PublishProcessor.create(); + TestSubscriberEx ts = new TestSubscriberEx<>(0L); + + source.onBackpressureLatest(e -> { + if (e == 3) { + throw new TestException("forced"); + } + }) + .subscribe(ts); + + ts.assertNoValues(); + + source.onNext(1); + source.onNext(2); + + ts.request(1); + + ts.assertValues(2); + + source.onNext(3); + source.onNext(4); + + ts.assertError(TestException.class); + ts.assertValues(2); + } + @Test public void synchronousDrop() { PublishProcessor source = PublishProcessor.create(); @@ -105,7 +170,7 @@ public void synchronousDrop() { } @Test - public void asynchronousDrop() throws InterruptedException { + public void asynchronousDrop() { TestSubscriberEx ts = new TestSubscriberEx(1L) { final Random rnd = new Random(); @Override @@ -133,6 +198,12 @@ public void onNext(Integer t) { int n = ts.values().size(); System.out.println("testAsynchronousDrop -> " + n); Assert.assertTrue("All events received?", n < m); + int previous = 0; + for (Integer current : ts.values()) { + Assert.assertTrue("The sequence must be increasing [current value=" + previous + + ", previous value=" + current + "]", previous <= current); + previous = current; + } } @Test diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureReduceTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureReduceTest.java new file mode 100644 index 00000000000..5f7b7ad9571 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureReduceTest.java @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.core.RxJavaTest; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.BiFunction; +import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.subscribers.TestSubscriber; +import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.TestSubscriberEx; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Random; +import java.util.concurrent.TimeUnit; + +public class FlowableOnBackpressureReduceTest extends RxJavaTest { + + static final BiFunction TEST_INT_REDUCER = (previous, current) -> previous + current + 50; + + static final BiFunction TEST_OBJECT_REDUCER = (previous, current) -> current; + + @Test + public void simple() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + + Flowable.range(1, 5).onBackpressureReduce(TEST_INT_REDUCER).subscribe(ts); + + ts.assertNoErrors(); + ts.assertTerminated(); + ts.assertValues(1, 2, 3, 4, 5); + } + + @Test + public void simpleError() { + TestSubscriberEx ts = new TestSubscriberEx<>(); + + Flowable.range(1, 5).concatWith(Flowable.error(new TestException())) + .onBackpressureReduce(TEST_INT_REDUCER).subscribe(ts); + + ts.assertTerminated(); + ts.assertError(TestException.class); + ts.assertValues(1, 2, 3, 4, 5); + } + + @Test + public void simpleBackpressure() { + TestSubscriber ts = new TestSubscriber<>(2L); + + Flowable.range(1, 5).onBackpressureReduce(TEST_INT_REDUCER).subscribe(ts); + + ts.assertNoErrors(); + ts.assertValues(1, 2); + ts.assertNotComplete(); + } + + @Test + public void synchronousDrop() { + PublishProcessor source = PublishProcessor.create(); + TestSubscriberEx ts = new TestSubscriberEx<>(0L); + + source.onBackpressureReduce(TEST_INT_REDUCER).subscribe(ts); + + ts.assertNoValues(); + + source.onNext(1); + ts.request(2); + + ts.assertValue(1); + + source.onNext(2); + + ts.assertValues(1, 2); + + source.onNext(3); + source.onNext(4); //3 + 4 + 50 == 57 + source.onNext(5); //57 + 5 + 50 == 112 + source.onNext(6); //112 + 6 + 50 == 168 + + ts.request(2); + + ts.assertValues(1, 2, 168); + + source.onNext(7); + + ts.assertValues(1, 2, 168, 7); + + source.onNext(8); + source.onNext(9); //8 + 9 + 50 == 67 + source.onComplete(); + + ts.request(1); + + ts.assertValues(1, 2, 168, 7, 67); + ts.assertNoErrors(); + ts.assertTerminated(); + } + + @Test + public void reduceBackpressuredSync() { + PublishProcessor source = PublishProcessor.create(); + TestSubscriberEx ts = new TestSubscriberEx<>(0L); + + source.onBackpressureReduce(Integer::sum).subscribe(ts); + + source.onNext(1); + source.onNext(2); + source.onNext(3); + + ts.request(1); + + ts.assertValuesOnly(6); + + source.onNext(4); + source.onComplete(); + + ts.assertValuesOnly(6); + + ts.request(1); + ts.assertResult(6, 4); + } + + private TestSubscriberEx createDelayedSubscriber() { + return new TestSubscriberEx(1L) { + final Random rnd = new Random(); + + @Override + public void onNext(T t) { + super.onNext(t); + if (rnd.nextDouble() < 0.001) { + try { + Thread.sleep(1); + } catch (InterruptedException ex) { + ex.printStackTrace(); + } + } + request(1); + } + }; + } + + private void assertValuesDropped(TestSubscriberEx ts, int totalValues) { + int n = ts.values().size(); + System.out.println("testAsynchronousDrop -> " + n); + Assert.assertTrue("All events received?", n < totalValues); + } + + private void assertIncreasingSequence(TestSubscriberEx ts) { + int previous = 0; + for (Integer current : ts.values()) { + Assert.assertTrue("The sequence must be increasing [current value=" + previous + + ", previous value=" + current + "]", previous <= current); + previous = current; + } + } + + @Test + public void asynchronousDrop() { + TestSubscriberEx ts = createDelayedSubscriber(); + int m = 100000; + Flowable.range(1, m) + .subscribeOn(Schedulers.computation()) + .onBackpressureReduce((previous, current) -> { + //in that case it works like onBackpressureLatest + //the output sequence of number must be increasing + return current; + }) + .observeOn(Schedulers.io()) + .subscribe(ts); + + ts.awaitDone(2, TimeUnit.SECONDS); + ts.assertTerminated(); + assertValuesDropped(ts, m); + assertIncreasingSequence(ts); + } + + @Test + public void asynchronousDrop2() { + TestSubscriberEx ts = createDelayedSubscriber(); + int m = 100000; + Flowable.rangeLong(1, m) + .subscribeOn(Schedulers.computation()) + .onBackpressureReduce(Long::sum) + .observeOn(Schedulers.io()) + .subscribe(ts); + + ts.awaitDone(2, TimeUnit.SECONDS); + ts.assertTerminated(); + assertValuesDropped(ts, m); + long sum = 0; + for (Long i : ts.values()) { + sum += i; + } + //sum = (A1 + An) * n / 2 = 100_001 * 50_000 = 50_000_00000 + 50_000 = 50_000_50_000 + Assert.assertEquals("Wrong sum: " + sum, 5000050000L, sum); + } + + @Test + public void nullPointerFromReducer() { + PublishProcessor source = PublishProcessor.create(); + TestSubscriberEx ts = new TestSubscriberEx<>(0); + source.onBackpressureReduce((l, r) -> null).subscribe(ts); + + source.onNext(1); + source.onNext(2); + + TestHelper.assertError(ts.errors(), 0, NullPointerException.class, "The reducer returned a null value"); + } + + @Test + public void exceptionFromReducer() { + PublishProcessor source = PublishProcessor.create(); + TestSubscriberEx ts = new TestSubscriberEx<>(0); + source.onBackpressureReduce((l, r) -> { + throw new TestException("Test exception"); + }).subscribe(ts); + + source.onNext(1); + source.onNext(2); + + TestHelper.assertError(ts.errors(), 0, TestException.class, "Test exception"); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.onBackpressureReduce(TEST_OBJECT_REDUCER)); + } + + @Test + public void take() { + Flowable.just(1, 2) + .onBackpressureReduce(TEST_INT_REDUCER) + .take(1) + .test() + .assertResult(1); + } + + @Test + public void dispose() { + TestHelper.checkDisposed(Flowable.never().onBackpressureReduce(TEST_OBJECT_REDUCER)); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().onBackpressureReduce(TEST_OBJECT_REDUCER)); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureReduceWithTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureReduceWithTest.java new file mode 100644 index 00000000000..32cee35603b --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnBackpressureReduceWithTest.java @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.core.RxJavaTest; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.BiFunction; +import io.reactivex.rxjava3.functions.Supplier; +import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.TestSubscriberEx; +import org.junit.Assert; +import org.junit.Test; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +public class FlowableOnBackpressureReduceWithTest extends RxJavaTest { + + private static BiFunction, T, List> createTestReducer() { + return (list, number) -> { + list.add(number); + return list; + }; + } + + private static Supplier> createTestSupplier() { + return ArrayList::new; + } + + @Test + public void simple() { + TestSubscriberEx> ts = new TestSubscriberEx<>(); + + Flowable.range(1, 5).onBackpressureReduce(createTestSupplier(), createTestReducer()).subscribe(ts); + + ts.assertNoErrors(); + ts.assertTerminated(); + ts.assertValues( + Collections.singletonList(1), + Collections.singletonList(2), + Collections.singletonList(3), + Collections.singletonList(4), + Collections.singletonList(5) + ); + } + + @Test + public void simpleError() { + TestSubscriberEx> ts = new TestSubscriberEx<>(); + + Flowable.range(1, 5).concatWith(Flowable.error(new TestException())) + .onBackpressureReduce(createTestSupplier(), createTestReducer()).subscribe(ts); + + ts.assertTerminated(); + ts.assertError(TestException.class); + ts.assertValues( + Collections.singletonList(1), + Collections.singletonList(2), + Collections.singletonList(3), + Collections.singletonList(4), + Collections.singletonList(5) + ); + } + + @Test + public void simpleBackpressure() { + TestSubscriberEx> ts = new TestSubscriberEx<>(2L); + + Flowable.range(1, 5).onBackpressureReduce(createTestSupplier(), createTestReducer()).subscribe(ts); + + ts.assertNoErrors(); + ts.assertValues( + Collections.singletonList(1), + Collections.singletonList(2) + ); + ts.assertNotComplete(); + } + + @Test + public void reduceBackpressuredSync() { + PublishProcessor source = PublishProcessor.create(); + TestSubscriberEx ts = new TestSubscriberEx<>(0L); + + source.onBackpressureReduce(() -> 0, Integer::sum).subscribe(ts); + + source.onNext(1); + source.onNext(2); + source.onNext(3); + + ts.request(1); + + ts.assertValuesOnly(6); + + source.onNext(4); + source.onComplete(); + + ts.assertValuesOnly(6); + + ts.request(1); + ts.assertResult(6, 4); + } + + @Test + public void synchronousDrop() { + PublishProcessor source = PublishProcessor.create(); + TestSubscriberEx> ts = new TestSubscriberEx<>(0L); + + source.onBackpressureReduce(createTestSupplier(), createTestReducer()).subscribe(ts); + + ts.assertNoValues(); + + source.onNext(1); + ts.request(2); + + ts.assertValues(Collections.singletonList(1)); + + source.onNext(2); + + ts.assertValues( + Collections.singletonList(1), + Collections.singletonList(2) + ); + + source.onNext(3); + source.onNext(4); + source.onNext(5); + source.onNext(6); + + ts.request(2); + + ts.assertValues( + Collections.singletonList(1), + Collections.singletonList(2), + Arrays.asList(3, 4, 5, 6) + ); + + source.onNext(7); + + ts.assertValues( + Collections.singletonList(1), + Collections.singletonList(2), + Arrays.asList(3, 4, 5, 6), + Collections.singletonList(7) + ); + + source.onNext(8); + source.onNext(9); + source.onComplete(); + + ts.request(1); + + ts.assertValues( + Collections.singletonList(1), + Collections.singletonList(2), + Arrays.asList(3, 4, 5, 6), + Collections.singletonList(7), + Arrays.asList(8, 9) + ); + ts.assertNoErrors(); + ts.assertTerminated(); + } + + private TestSubscriberEx createDelayedSubscriber() { + return new TestSubscriberEx(1L) { + final Random rnd = new Random(); + + @Override + public void onNext(T t) { + super.onNext(t); + if (rnd.nextDouble() < 0.001) { + try { + Thread.sleep(1); + } catch (InterruptedException ex) { + ex.printStackTrace(); + } + } + request(1); + } + }; + } + + private void assertValuesDropped(TestSubscriberEx ts, int totalValues) { + int n = ts.values().size(); + System.out.println("testAsynchronousDrop -> " + n); + Assert.assertTrue("All events received?", n < totalValues); + } + + private void assertIncreasingSequence(TestSubscriberEx ts) { + int previous = 0; + for (Integer current : ts.values()) { + Assert.assertTrue("The sequence must be increasing [current value=" + previous + + ", previous value=" + current + "]", previous <= current); + previous = current; + } + } + + @Test + public void asynchronousDrop() { + TestSubscriberEx ts = createDelayedSubscriber(); + int m = 100000; + Flowable.range(1, m) + .subscribeOn(Schedulers.computation()) + .onBackpressureReduce((Supplier>) Collections::emptyList, (list, current) -> { + //in that case it works like onBackpressureLatest + //the output sequence of number must be increasing + return Collections.singletonList(current); + }) + .observeOn(Schedulers.io()) + .concatMap(Flowable::fromIterable) + .subscribe(ts); + + ts.awaitDone(2, TimeUnit.SECONDS); + ts.assertTerminated(); + assertValuesDropped(ts, m); + assertIncreasingSequence(ts); + } + + @Test + public void asynchronousDrop2() { + TestSubscriberEx ts = createDelayedSubscriber(); + int m = 100000; + Flowable.rangeLong(1, m) + .subscribeOn(Schedulers.computation()) + .onBackpressureReduce(createTestSupplier(), createTestReducer()) + .observeOn(Schedulers.io()) + .concatMap(list -> Flowable.just(list.stream().reduce(Long::sum).orElseThrow(() -> { + throw new IllegalArgumentException("No value in list"); + }))) + .subscribe(ts); + + ts.awaitDone(2, TimeUnit.SECONDS); + ts.assertTerminated(); + assertValuesDropped(ts, m); + long sum = 0; + for (Long i : ts.values()) { + sum += i; + } + //sum = (A1 + An) * n / 2 = 100_001 * 50_000 = 50_000_00000 + 50_000 = 50_000_50_000 + Assert.assertEquals("Wrong sum: " + sum, 5000050000L, sum); + } + + @Test + public void nullPointerFromReducer() { + PublishProcessor source = PublishProcessor.create(); + TestSubscriberEx> ts = new TestSubscriberEx<>(0L); + source.onBackpressureReduce(createTestSupplier(), (BiFunction, ? super Integer, List>) (list, number) -> null).subscribe(ts); + + source.onNext(1); + source.onNext(2); + + TestHelper.assertError(ts.errors(), 0, NullPointerException.class, "The reducer returned a null value"); + } + + @Test + public void nullPointerFromSupplier() { + PublishProcessor source = PublishProcessor.create(); + TestSubscriberEx> ts = new TestSubscriberEx<>(0L); + source.onBackpressureReduce(() -> null, createTestReducer()).subscribe(ts); + + source.onNext(1); + source.onNext(2); + + TestHelper.assertError(ts.errors(), 0, NullPointerException.class, "The supplier returned a null value"); + } + + @Test + public void exceptionFromReducer() { + PublishProcessor source = PublishProcessor.create(); + TestSubscriberEx> ts = new TestSubscriberEx<>(0L); + source.onBackpressureReduce(createTestSupplier(), (BiFunction, ? super Integer, List>) (l, r) -> { + throw new TestException("Test exception"); + }).subscribe(ts); + + source.onNext(1); + source.onNext(2); + + TestHelper.assertError(ts.errors(), 0, TestException.class, "Test exception"); + } + + @Test + public void exceptionFromSupplier() { + PublishProcessor source = PublishProcessor.create(); + TestSubscriberEx> ts = new TestSubscriberEx<>(0L); + source.onBackpressureReduce(() -> { + throw new TestException("Test exception"); + }, createTestReducer()).subscribe(ts); + + source.onNext(1); + source.onNext(2); + + TestHelper.assertError(ts.errors(), 0, TestException.class, "Test exception"); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.onBackpressureReduce(createTestSupplier(), createTestReducer())); + } + + @Test + public void take() { + Flowable.just(1, 2) + .onBackpressureReduce(createTestSupplier(), createTestReducer()) + .take(1) + .test() + .assertResult(Collections.singletonList(1)); + } + + @Test + public void dispose() { + TestHelper.checkDisposed(Flowable.never().onBackpressureReduce(createTestSupplier(), createTestReducer())); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().onBackpressureReduce(createTestSupplier(), createTestReducer())); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorCompleteTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorCompleteTest.java new file mode 100644 index 00000000000..0a6f137ce24 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorCompleteTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.subscribers.TestSubscriber; +import io.reactivex.rxjava3.testsupport.*; + +public class FlowableOnErrorCompleteTest { + + @Test + public void normal() { + Flowable.range(1, 10) + .onErrorComplete() + .test() + .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + + @Test + public void normalBackpressured() { + Flowable.range(1, 10) + .onErrorComplete() + .test(0) + .assertEmpty() + .requestMore(3) + .assertValuesOnly(1, 2, 3) + .requestMore(3) + .assertValuesOnly(1, 2, 3, 4, 5, 6) + .requestMore(4) + .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + + @Test + public void empty() { + Flowable.empty() + .onErrorComplete() + .test() + .assertResult(); + } + + @Test + public void error() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Flowable.error(new TestException()) + .onErrorComplete() + .test() + .assertResult(); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void errorMatches() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Flowable.error(new TestException()) + .onErrorComplete(error -> error instanceof TestException) + .test() + .assertResult(); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void errorNotMatches() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Flowable.error(new IOException()) + .onErrorComplete(error -> error instanceof TestException) + .test() + .assertFailure(IOException.class); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void errorPredicateCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + TestSubscriberEx ts = Flowable.error(new IOException()) + .onErrorComplete(error -> { throw new TestException(); }) + .subscribeWith(new TestSubscriberEx<>()) + .assertFailure(CompositeException.class); + + TestHelper.assertError(ts, 0, IOException.class); + TestHelper.assertError(ts, 1, TestException.class); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void itemsThenError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Flowable.range(1, 5) + .map(v -> 4 / (3 - v)) + .onErrorComplete() + .test() + .assertResult(2, 4); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void cancel() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = pp + .onErrorComplete() + .test(); + + assertTrue("No subscribers?!", pp.hasSubscribers()); + + ts.cancel(); + + assertFalse("Still subscribers?!", pp.hasSubscribers()); + } + + @Test + public void onSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.onErrorComplete()); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorResumeNextViaFlowableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorResumeNextViaFlowableTest.java index b8829893fab..8b94b0d6f0a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorResumeNextViaFlowableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorResumeNextViaFlowableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorResumeNextViaFunctionTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorResumeNextViaFunctionTest.java index 51de11ae7b7..982ffecd1d1 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorResumeNextViaFunctionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorResumeNextViaFunctionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorReturnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorReturnTest.java index ecde026f95e..15007f0228f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorReturnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableOnErrorReturnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishFunctionTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishFunctionTest.java index 69ed3a4aed8..5511fd0123c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishFunctionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishFunctionTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.operators.flowable; @@ -19,6 +16,7 @@ import static org.junit.Assert.*; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.junit.*; @@ -26,7 +24,6 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; -import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.processors.PublishProcessor; @@ -39,12 +36,9 @@ public class FlowablePublishFunctionTest extends RxJavaTest { public void concatTakeFirstLastCompletes() { TestSubscriber ts = new TestSubscriber<>(); - Flowable.range(1, 3).publish(new Function, Flowable>() { - @Override - public Flowable apply(Flowable f) { - return Flowable.concat(f.take(5), f.takeLast(5)); - } - }).subscribe(ts); + Flowable.range(1, 3) + .publish(f -> Flowable.concat(f.take(5), f.takeLast(5))) + .subscribe(ts); ts.assertValues(1, 2, 3); ts.assertNoErrors(); @@ -55,12 +49,9 @@ public Flowable apply(Flowable f) { public void concatTakeFirstLastBackpressureCompletes() { TestSubscriber ts = TestSubscriber.create(0L); - Flowable.range(1, 6).publish(new Function, Flowable>() { - @Override - public Flowable apply(Flowable f) { - return Flowable.concat(f.take(5), f.takeLast(5)); - } - }).subscribe(ts); + Flowable.range(1, 6) + .publish(f -> Flowable.concat(f.take(5), f.takeLast(5))) + .subscribe(ts); ts.assertNoValues(); ts.assertNoErrors(); @@ -86,12 +77,7 @@ public void canBeCancelled() { PublishProcessor pp = PublishProcessor.create(); - pp.publish(new Function, Flowable>() { - @Override - public Flowable apply(Flowable f) { - return Flowable.concat(f.take(5), f.takeLast(5)); - } - }).subscribe(ts); + pp.publish(f -> Flowable.concat(f.take(5), f.takeLast(5))).subscribe(ts); pp.onNext(1); pp.onNext(2); @@ -108,8 +94,7 @@ public Flowable apply(Flowable f) { @Test public void invalidPrefetch() { try { - Flowable.never().publish( - Functions.>identity(), -99); + Flowable.never().publish(Functions.identity(), -99); fail("Didn't throw IllegalArgumentException"); } catch (IllegalArgumentException ex) { Assert.assertEquals("prefetch > 0 required but it was -99", ex.getMessage()); @@ -122,12 +107,7 @@ public void takeCompletes() { PublishProcessor pp = PublishProcessor.create(); - pp.publish(new Function, Flowable>() { - @Override - public Flowable apply(Flowable f) { - return f.take(1); - } - }).subscribe(ts); + pp.publish(f -> f.take(1)).subscribe(ts); pp.onNext(1); @@ -153,12 +133,7 @@ public void onStart() { PublishProcessor pp = PublishProcessor.create(); - pp.publish(new Function, Flowable>() { - @Override - public Flowable apply(Flowable f) { - return f.take(1); - } - }).subscribe(ts); + pp.publish(f -> f.take(1)).subscribe(ts); Assert.assertEquals(1, startCount.get()); } @@ -169,12 +144,7 @@ public void takeCompletesUnsafe() { PublishProcessor pp = PublishProcessor.create(); - pp.publish(new Function, Flowable>() { - @Override - public Flowable apply(Flowable f) { - return f.take(1); - } - }).subscribe(ts); + pp.publish(f -> f.take(1)).subscribe(ts); pp.onNext(1); @@ -191,12 +161,7 @@ public void directCompletesUnsafe() { PublishProcessor pp = PublishProcessor.create(); - pp.publish(new Function, Flowable>() { - @Override - public Flowable apply(Flowable f) { - return f; - } - }).subscribe(ts); + pp.publish(Functions.identity()).subscribe(ts); pp.onNext(1); pp.onComplete(); @@ -214,12 +179,7 @@ public void overflowMissingBackpressureException() { PublishProcessor pp = PublishProcessor.create(); - pp.publish(new Function, Flowable>() { - @Override - public Flowable apply(Flowable f) { - return f; - } - }).subscribe(ts); + pp.publish(Functions.identity()).subscribe(ts); for (int i = 0; i < Flowable.bufferSize() * 2; i++) { pp.onNext(i); @@ -229,7 +189,7 @@ public Flowable apply(Flowable f) { ts.assertError(MissingBackpressureException.class); ts.assertNotComplete(); - Assert.assertEquals("Could not emit value due to lack of requests", + Assert.assertEquals(MissingBackpressureException.DEFAULT_MESSAGE, ts.errors().get(0).getMessage()); Assert.assertFalse("Source has subscribers?", pp.hasSubscribers()); } @@ -240,12 +200,7 @@ public void overflowMissingBackpressureExceptionDelayed() { PublishProcessor pp = PublishProcessor.create(); - new FlowablePublishMulticast<>(pp, new Function, Flowable>() { - @Override - public Flowable apply(Flowable f) { - return f; - } - }, Flowable.bufferSize(), true).subscribe(ts); + new FlowablePublishMulticast<>(pp, Functions.identity(), Flowable.bufferSize(), true).subscribe(ts); for (int i = 0; i < Flowable.bufferSize() * 2; i++) { pp.onNext(i); @@ -257,29 +212,23 @@ public Flowable apply(Flowable f) { ts.assertError(MissingBackpressureException.class); ts.assertNotComplete(); - Assert.assertEquals("Could not emit value due to lack of requests", ts.errors().get(0).getMessage()); + Assert.assertEquals(MissingBackpressureException.DEFAULT_MESSAGE, ts.errors().get(0).getMessage()); Assert.assertFalse("Source has subscribers?", pp.hasSubscribers()); } @Test public void emptyIdentityMapped() { Flowable.empty() - .publish(Functions.>identity()) + .publish(Functions.identity()) .test() - .assertResult() - ; + .assertResult(); } @Test public void independentlyMapped() { PublishProcessor pp = PublishProcessor.create(); - TestSubscriber ts = pp.publish(new Function, Publisher>() { - @Override - public Publisher apply(Flowable v) throws Exception { - return Flowable.range(1, 5); - } - }).test(0); + TestSubscriber ts = pp.publish(v -> Flowable.range(1, 5)).test(0); assertTrue("pp has no Subscribers?!", pp.hasSubscribers()); @@ -296,12 +245,7 @@ public Publisher apply(Flowable v) throws Exception { @Test public void badSource() { - TestHelper.checkBadSourceFlowable(new Function, Object>() { - @Override - public Object apply(Flowable f) throws Exception { - return f.publish(Functions.>identity()); - } - }, false, 1, 1, 1); + TestHelper.checkBadSourceFlowable(f -> f.publish(Functions.identity()), false, 1, 1, 1); } @Test @@ -315,7 +259,7 @@ protected void subscribeActual(Subscriber s) { } } } - .publish(Functions.>identity(), 8) + .publish(Functions.identity(), 8) .test(0) .assertFailure(MissingBackpressureException.class); } @@ -323,12 +267,7 @@ protected void subscribeActual(Subscriber s) { @Test public void errorResubscribe() { Flowable.error(new TestException()) - .publish(new Function, Publisher>() { - @Override - public Publisher apply(Flowable f) throws Exception { - return f.onErrorResumeWith(f); - } - }) + .publish(f -> f.onErrorResumeWith(f)) .test() .assertFailure(TestException.class); } @@ -336,21 +275,18 @@ public Publisher apply(Flowable f) throws Exception { @Test public void fusedInputCrash() { Flowable.just(1) - .map(new Function() { - @Override - public Integer apply(Integer v) throws Exception { - throw new TestException(); - } + .map(v -> { + throw new TestException(); }) - .publish(Functions.>identity()) + .publish(Functions.identity()) .test() .assertFailure(TestException.class); } @Test public void error() { - new FlowablePublishMulticast<>(Flowable.just(1).concatWith(Flowable.error(new TestException())), - Functions.>identity(), 16, true) + new FlowablePublishMulticast<>(Flowable.just(1).concatWith(Flowable.error(new TestException())), + Functions.identity(), 16, true) .test() .assertFailure(TestException.class, 1); } @@ -358,7 +294,7 @@ public void error() { @Test public void backpressuredEmpty() { Flowable.empty() - .publish(Functions.>identity()) + .publish(Functions.identity()) .test(0L) .assertResult(); } @@ -366,7 +302,7 @@ public void backpressuredEmpty() { @Test public void oneByOne() { Flowable.range(1, 10) - .publish(Functions.>identity()) + .publish(Functions.identity()) .rebatchRequests(1) .test() .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); @@ -387,7 +323,7 @@ public void onNext(Integer t) { } }; - pp.publish(Functions.>identity()).subscribe(ts); + pp.publish(Functions.identity()).subscribe(ts); pp.onNext(1); @@ -399,12 +335,7 @@ public void onNext(Integer t) { @Test public void inputOutputSubscribeRace() { Flowable source = Flowable.just(1) - .publish(new Function, Publisher>() { - @Override - public Publisher apply(Flowable f) throws Exception { - return f.subscribeOn(Schedulers.single()); - } - }); + .publish(f -> f.subscribeOn(Schedulers.single())); for (int i = 0; i < 500; i++) { source.test() @@ -416,7 +347,7 @@ public Publisher apply(Flowable f) throws Exception { @Test public void inputOutputSubscribeRace2() { Flowable source = Flowable.just(1).subscribeOn(Schedulers.single()) - .publish(Functions.>identity()); + .publish(Functions.identity()); for (int i = 0; i < 500; i++) { source.test() @@ -431,30 +362,19 @@ public void sourceSubscriptionDelayed() { final TestSubscriber ts1 = new TestSubscriber<>(0L); Flowable.just(1) - .publish(new Function, Publisher>() { - @Override - public Publisher apply(final Flowable f) throws Exception { - Runnable r1 = new Runnable() { - @Override - public void run() { - f.subscribe(ts1); - } - }; - - Runnable r2 = new Runnable() { - @Override - public void run() { + .publish(f -> { + Runnable r1 = () -> f.subscribe(ts1); + + Runnable r2 = () -> { for (int j = 0; j < 100; j++) { ts1.request(1); } - } - }; + }; - TestHelper.race(r1, r2); - return f; - } - }).test() - .assertResult(1); + TestHelper.race(r1, r2); + return f; + }).test() + .assertResult(1); ts1.assertResult(1); } @@ -463,24 +383,9 @@ public void run() { @Test public void longFlow() { Flowable.range(1, 1000000) - .publish(new Function, Publisher>() { - @Override - public Publisher apply(Flowable v) throws Exception { - return Flowable.mergeArray( - v.filter(new Predicate() { - @Override - public boolean test(Integer w) throws Exception { - return w % 2 == 0; - } - }), - v.filter(new Predicate() { - @Override - public boolean test(Integer w) throws Exception { - return w % 2 != 0; - } - })); - } - }) + .publish(v -> Flowable.mergeArray( + v.filter(w -> w % 2 == 0), + v.filter(w -> w % 2 != 0))) .takeLast(1) .test() .assertResult(1000000); @@ -489,24 +394,9 @@ public boolean test(Integer w) throws Exception { @Test public void longFlow2() { Flowable.range(1, 100000) - .publish(new Function, Publisher>() { - @Override - public Publisher apply(Flowable v) throws Exception { - return Flowable.mergeArray( - v.filter(new Predicate() { - @Override - public boolean test(Integer w) throws Exception { - return w % 2 == 0; - } - }), - v.filter(new Predicate() { - @Override - public boolean test(Integer w) throws Exception { - return w % 2 != 0; - } - })); - } - }) + .publish(v -> Flowable.mergeArray( + v.filter(w -> w % 2 == 0), + v.filter(w -> w % 2 != 0))) .test() .assertValueCount(100000) .assertNoErrors() @@ -516,26 +406,45 @@ public boolean test(Integer w) throws Exception { @Test public void longFlowHidden() { Flowable.range(1, 1000000).hide() - .publish(new Function, Publisher>() { - @Override - public Publisher apply(Flowable v) throws Exception { - return Flowable.mergeArray( - v.filter(new Predicate() { - @Override - public boolean test(Integer w) throws Exception { - return w % 2 == 0; - } - }), - v.filter(new Predicate() { - @Override - public boolean test(Integer w) throws Exception { - return w % 2 != 0; - } - })); - } - }) + .publish(v -> Flowable.mergeArray( + v.filter(w -> w % 2 == 0), + v.filter(w -> w % 2 != 0))) .takeLast(1) .test() .assertResult(1000000); } + + @Test + public void noUpstreamCancelOnCasualChainClose() { + AtomicBoolean parentUpstreamCancelled = new AtomicBoolean(false); + Flowable.range(1, 10) + .doOnCancel(() -> parentUpstreamCancelled.set(true)) + .publish(Functions.identity()) + .test() + .awaitDone(1, TimeUnit.SECONDS); + assertFalse("Unnecessary upstream .cancel() call in FlowablePublishMulticast", parentUpstreamCancelled.get()); + } + + @Test + public void noUpstreamCancelOnCasualChainCloseWithInnerCancels() { + AtomicBoolean parentUpstreamCancelled = new AtomicBoolean(false); + Flowable.range(1, 10) + .doOnCancel(() -> parentUpstreamCancelled.set(true)) + .publish(v -> Flowable.concat(v.take(1), v.skip(5))) + .test() + .awaitDone(1, TimeUnit.SECONDS); + assertFalse("Unnecessary upstream .cancel() call in FlowablePublishMulticast", parentUpstreamCancelled.get()); + } + + @Test + public void upstreamCancelOnDownstreamCancel() { + AtomicBoolean parentUpstreamCancelled = new AtomicBoolean(false); + Flowable.range(1, 10) + .doOnCancel(() -> parentUpstreamCancelled.set(true)) + .publish(Functions.identity()) + .take(1) + .test() + .awaitDone(1, TimeUnit.SECONDS); + assertTrue("Upstream .cancel() not called in FlowablePublishMulticast", parentUpstreamCancelled.get()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishMulticastTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishMulticastTest.java index 0fb61a84c52..0e1bdbbdc02 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishMulticastTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishMulticastTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,9 +20,9 @@ import org.junit.Test; import io.reactivex.rxjava3.core.RxJavaTest; -import io.reactivex.rxjava3.internal.fuseable.QueueSubscription; import io.reactivex.rxjava3.internal.operators.flowable.FlowablePublishMulticast.*; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.UnicastProcessor; import io.reactivex.rxjava3.subscribers.TestSubscriber; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishTest.java index 0dffd13798b..c3355e9a38f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowablePublishTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -905,9 +905,9 @@ public void subscribe(FlowableEmitter s) throws Exception { .test(0L) // 3.x emits errors last, even the full queue errors .requestMore(10) - .assertFailure(MissingBackpressureException.class, 0, 1, 2, 3, 4, 5, 6, 7); + .assertFailure(QueueOverflowException.class, 0, 1, 2, 3, 4, 5, 6, 7); - TestHelper.assertError(errors, 0, MissingBackpressureException.class); + TestHelper.assertError(errors, 0, QueueOverflowException.class); } finally { RxJavaPlugins.reset(); } @@ -1596,7 +1596,7 @@ protected void subscribeActual(Subscriber s) { .refCount() .test(0) .requestMore(1) - .assertFailure(MissingBackpressureException.class, 1); + .assertFailure(QueueOverflowException.class, 1); } @Test @@ -1697,4 +1697,110 @@ public void disposeResets() { ts.assertValuesOnly(1); } + + @Test(expected = TestException.class) + public void connectDisposeCrash() { + ConnectableFlowable cf = Flowable.never().publish(); + + cf.connect(); + + cf.connect(d -> { throw new TestException(); }); + } + + @Test + public void resetWhileNotConnectedIsNoOp() { + ConnectableFlowable cf = Flowable.never().publish(); + + cf.reset(); + } + + @Test + public void resetWhileActiveIsNoOp() { + ConnectableFlowable cf = Flowable.never().publish(); + + cf.connect(); + + cf.reset(); + } + + @Test + public void crossCancelOnComplete() { + TestSubscriber ts1 = new TestSubscriber<>(); + TestSubscriber ts2 = new TestSubscriber() { + @Override + public void onComplete() { + super.onComplete(); + ts1.cancel(); + } + }; + + PublishProcessor pp = PublishProcessor.create(); + + ConnectableFlowable cf = pp.publish(); + + cf.subscribe(ts2); + cf.subscribe(ts1); + + cf.connect(); + + pp.onComplete(); + + ts2.assertResult(); + + ts1.assertEmpty(); + } + + @Test + public void crossCancelOnError() { + TestSubscriber ts1 = new TestSubscriber<>(); + TestSubscriber ts2 = new TestSubscriber() { + @Override + public void onError(Throwable t) { + super.onError(t); + ts1.cancel(); + } + }; + + PublishProcessor pp = PublishProcessor.create(); + + ConnectableFlowable cf = pp.publish(); + + cf.subscribe(ts2); + cf.subscribe(ts1); + + cf.connect(); + + pp.onError(new TestException()); + + ts2.assertFailure(TestException.class); + + ts1.assertEmpty(); + } + + @Test + public void disposeNoNeedForReset() { + PublishProcessor pp = PublishProcessor.create(); + + ConnectableFlowable cf = pp.publish(); + + TestSubscriber ts = cf.test(); + + Disposable d = cf.connect(); + + pp.onNext(1); + + d.dispose(); + + ts = cf.test(); + + ts.assertEmpty(); + + cf.connect(); + + ts.assertEmpty(); + + pp.onNext(2); + + ts.assertValuesOnly(2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRangeLongTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRangeLongTest.java index 96401918ef2..bc24ab787c9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRangeLongTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRangeLongTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.subscribers.*; import io.reactivex.rxjava3.testsupport.*; @@ -539,4 +539,44 @@ public boolean test(Long v) throws Exception { ts.assertResult(2L, 4L); } + + @Test + public void slowPathCancelBeforeComplete() { + Flowable.rangeLong(1, 2) + .take(2) + .test() + .assertResult(1L, 2L); + } + + @Test + public void conditionalFastPathCancelBeforeComplete() { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.rangeLong(1, 2) + .compose(TestHelper.conditional()) + .doOnNext(v -> { + if (v == 2L) { + ts.cancel(); + } + }) + .subscribe(ts); + + ts.assertValuesOnly(1L, 2L); + } + + @Test + public void conditionalSlowPathTake() { + TestSubscriber ts = new TestSubscriber<>(4); + + Flowable.rangeLong(1, 3) + .compose(TestHelper.conditional()) + .doOnNext(v -> { + if (v == 2L) { + ts.cancel(); + } + }) + .subscribe(ts); + + ts.assertValuesOnly(1L, 2L); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRangeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRangeTest.java index 39ab84ad63d..53264bddc08 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRangeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRangeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.subscribers.*; import io.reactivex.rxjava3.testsupport.*; @@ -590,4 +590,28 @@ public void onNext(Integer t) { ts.assertResult(1, 2); } + + @Test + public void slowPathCancelBeforeComplete() { + Flowable.range(1, 2) + .take(2) + .test() + .assertResult(1, 2); + } + + @Test + public void conditionalFastPatchCancelBeforeComplete() { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.range(1, 2) + .compose(TestHelper.conditional()) + .doOnNext(v -> { + if (v == 2) { + ts.cancel(); + } + }) + .subscribe(ts); + + ts.assertValuesOnly(1, 2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceTest.java index bc7d1e8ecea..16b491a352e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -530,4 +530,9 @@ public Integer apply(Integer a, Integer b) throws Exception { RxJavaPlugins.reset(); } } + + @Test + public void doubleOnSubscribeFlowable() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.reduce((a, b) -> a).toFlowable()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceWithSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceWithSingleTest.java index d3da48ffe54..3de991aa2ed 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceWithSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReduceWithSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRefCountTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRefCountTest.java index 169409ed1b4..48fbb633ae9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRefCountTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRefCountTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,7 +45,25 @@ public class FlowableRefCountTest extends RxJavaTest { @Test - public void refCountAsync() { + public void refCountAsync() throws InterruptedException { + // Flaky + for (int i = 0; i < 10; i++) { + try { + refCountAsyncActual(); + return; + } catch (AssertionError ex) { + if (i == 9) { + throw ex; + } + Thread.sleep((int)(200 * (Math.random() * 10 + 1))); + } + } + } + + /** + * Tries to coordinate async counting but it is flaky due to the low 10s of milliseconds. + */ + void refCountAsyncActual() { final AtomicInteger subscribeCount = new AtomicInteger(); final AtomicInteger nextCount = new AtomicInteger(); Flowable r = Flowable.interval(0, 20, TimeUnit.MILLISECONDS) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeatTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeatTest.java index 29959688ad2..9086c32a87a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeatTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRepeatTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReplayEagerTruncateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReplayEagerTruncateTest.java index f263b98f669..d2a4ba56da2 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReplayEagerTruncateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReplayEagerTruncateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -732,7 +732,14 @@ public boolean isDisposed() { @Test public void boundedReplayBuffer() { - BoundedReplayBuffer buf = new BoundedReplayBuffer<>(true); + BoundedReplayBuffer buf = new BoundedReplayBuffer(true) { + private static final long serialVersionUID = -9081211580719235896L; + + @Override + void truncate() { + } + }; + buf.addLast(new Node(1, 0)); buf.addLast(new Node(2, 1)); buf.addLast(new Node(3, 2)); @@ -1916,19 +1923,6 @@ public ReplayBuffer get() throws Exception { .assertFailure(TestException.class); } - @Test - public void currentDisposedWhenConnecting() { - FlowableReplay fr = (FlowableReplay)FlowableReplay.create(Flowable.never(), 16, true); - fr.connect(); - - fr.current.get().dispose(); - assertTrue(fr.current.get().isDisposed()); - - fr.connect(); - - assertFalse(fr.current.get().isDisposed()); - } - @Test public void noBoundedRetentionViaThreadLocal() throws Exception { Flowable source = Flowable.range(1, 200) @@ -2268,4 +2262,85 @@ public void timeAndSizeNoTerminalTruncationOnTimechange() { .assertComplete() .assertNoErrors(); } + + @Test + public void disposeNoNeedForResetSizeBound() { + PublishProcessor pp = PublishProcessor.create(); + + ConnectableFlowable cf = pp.replay(10, true); + + TestSubscriber ts = cf.test(); + + Disposable d = cf.connect(); + + pp.onNext(1); + + d.dispose(); + + ts = cf.test(); + + ts.assertEmpty(); + + cf.connect(); + + ts.assertEmpty(); + + pp.onNext(2); + + ts.assertValuesOnly(2); + } + + @Test + public void disposeNoNeedForResetTimeBound() { + PublishProcessor pp = PublishProcessor.create(); + + ConnectableFlowable cf = pp.replay(10, TimeUnit.MINUTES, Schedulers.single(), true); + + TestSubscriber ts = cf.test(); + + Disposable d = cf.connect(); + + pp.onNext(1); + + d.dispose(); + + ts = cf.test(); + + ts.assertEmpty(); + + cf.connect(); + + ts.assertEmpty(); + + pp.onNext(2); + + ts.assertValuesOnly(2); + } + + @Test + public void disposeNoNeedForResetTimeAndSIzeBound() { + PublishProcessor pp = PublishProcessor.create(); + + ConnectableFlowable cf = pp.replay(10, 10, TimeUnit.MINUTES, Schedulers.single(), true); + + TestSubscriber ts = cf.test(); + + Disposable d = cf.connect(); + + pp.onNext(1); + + d.dispose(); + + ts = cf.test(); + + ts.assertEmpty(); + + cf.connect(); + + ts.assertEmpty(); + + pp.onNext(2); + + ts.assertValuesOnly(2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReplayTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReplayTest.java index 67763fce0b9..b644629a6de 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReplayTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableReplayTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,6 +17,7 @@ import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.io.IOException; import java.lang.management.*; import java.util.*; import java.util.concurrent.*; @@ -37,6 +38,7 @@ import io.reactivex.rxjava3.internal.fuseable.HasUpstreamPublisher; import io.reactivex.rxjava3.internal.operators.flowable.FlowableReplay.*; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.internal.util.BackpressureHelper; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.schedulers.*; @@ -44,6 +46,7 @@ import io.reactivex.rxjava3.testsupport.*; public class FlowableReplayTest extends RxJavaTest { + @Test public void bufferedReplay() { PublishProcessor source = PublishProcessor.create(); @@ -732,7 +735,14 @@ public boolean isDisposed() { @Test public void boundedReplayBuffer() { - BoundedReplayBuffer buf = new BoundedReplayBuffer<>(false); + BoundedReplayBuffer buf = new BoundedReplayBuffer(false) { + private static final long serialVersionUID = -9081211580719235896L; + + @Override + void truncate() { + } + }; + buf.addLast(new Node(1, 0)); buf.addLast(new Node(2, 1)); buf.addLast(new Node(3, 2)); @@ -760,6 +770,19 @@ public void boundedReplayBuffer() { } + @Test(expected = IllegalStateException.class) + public void boundedRemoveFirstOneItemOnly() { + BoundedReplayBuffer buf = new BoundedReplayBuffer(false) { + private static final long serialVersionUID = -9081211580719235896L; + + @Override + void truncate() { + } + }; + + buf.removeFirst(); + } + @Test public void timedAndSizedTruncation() { TestScheduler test = new TestScheduler(); @@ -965,7 +988,9 @@ public void take() { TestSubscriberEx ts = new TestSubscriberEx<>(); Flowable cached = Flowable.range(1, 100).replay().autoConnect(); - cached.take(10).subscribe(ts); + cached + .take(10) + .subscribe(ts); ts.assertNoErrors(); ts.assertTerminated(); @@ -1079,7 +1104,7 @@ public void valuesAndThenError() { } @Test - public void unsafeChildThrows() { + public void unsafeChildOnNextThrows() { final AtomicInteger count = new AtomicInteger(); Flowable source = Flowable.range(1, 100) @@ -1107,6 +1132,52 @@ public void onNext(Integer t) { ts.assertError(TestException.class); } + @Test + public void unsafeChildOnErrorThrows() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Flowable source = Flowable.error(new IOException()) + .replay() + .autoConnect(); + + TestSubscriber ts = new TestSubscriber() { + @Override + public void onError(Throwable t) { + super.onError(t); + throw new TestException(); + } + }; + + source.subscribe(ts); + + ts.assertFailure(IOException.class); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void unsafeChildOnCompleteThrows() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Flowable source = Flowable.empty() + .replay() + .autoConnect(); + + TestSubscriber ts = new TestSubscriber() { + @Override + public void onComplete() { + super.onComplete(); + throw new TestException(); + } + }; + + source.subscribe(ts); + + ts.assertResult(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + @Test public void unboundedLeavesEarly() { PublishProcessor source = PublishProcessor.create(); @@ -1917,19 +1988,6 @@ public ReplayBuffer get() throws Exception { .assertFailure(TestException.class); } - @Test - public void currentDisposedWhenConnecting() { - FlowableReplay fr = (FlowableReplay)FlowableReplay.create(Flowable.never(), 16, false); - fr.connect(); - - fr.current.get().dispose(); - assertTrue(fr.current.get().isDisposed()); - - fr.connect(); - - assertFalse(fr.current.get().isDisposed()); - } - @Test public void noBoundedRetentionViaThreadLocal() throws Exception { Flowable source = Flowable.range(1, 200) @@ -1992,4 +2050,240 @@ public void accept(byte[] v) throws Exception { + " -> " + after.get() / 1024.0 / 1024.0); } } + + @Test + public void unsafeChildOnNextThrowsSizeBound() { + final AtomicInteger count = new AtomicInteger(); + + Flowable source = Flowable.range(1, 100) + .doOnNext(new Consumer() { + @Override + public void accept(Integer t) { + count.getAndIncrement(); + } + }) + .replay(1000).autoConnect(); + + TestSubscriber ts = new TestSubscriber() { + @Override + public void onNext(Integer t) { + throw new TestException(); + } + }; + + source.subscribe(ts); + + Assert.assertEquals(100, count.get()); + + ts.assertNoValues(); + ts.assertNotComplete(); + ts.assertError(TestException.class); + } + + @Test + public void unsafeChildOnErrorThrowsSizeBound() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Flowable source = Flowable.error(new IOException()) + .replay(1000) + .autoConnect(); + + TestSubscriber ts = new TestSubscriber() { + @Override + public void onError(Throwable t) { + super.onError(t); + throw new TestException(); + } + }; + + source.subscribe(ts); + + ts.assertFailure(IOException.class); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void unsafeChildOnCompleteThrowsSizeBound() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Flowable source = Flowable.empty() + .replay(1000) + .autoConnect(); + + TestSubscriber ts = new TestSubscriber() { + @Override + public void onComplete() { + super.onComplete(); + throw new TestException(); + } + }; + + source.subscribe(ts); + + ts.assertResult(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test(expected = TestException.class) + public void connectDisposeCrash() { + ConnectableFlowable cf = Flowable.never().replay(); + + cf.connect(); + + cf.connect(d -> { throw new TestException(); }); + } + + @Test + public void resetWhileNotConnectedIsNoOp() { + ConnectableFlowable cf = Flowable.never().replay(); + + cf.reset(); + } + + @Test + public void resetWhileActiveIsNoOp() { + ConnectableFlowable cf = Flowable.never().replay(); + + cf.connect(); + + cf.reset(); + } + + @Test + public void delayedUpstreamSubscription() { + AtomicReference> ref = new AtomicReference<>(); + Flowable f = Flowable.unsafeCreate(ref::set); + + TestSubscriber ts = f.replay() + .autoConnect() + .test(); + + AtomicLong requested = new AtomicLong(); + + ref.get().onSubscribe(new Subscription() { + @Override + public void request(long n) { + BackpressureHelper.add(requested, n); + } + + @Override + public void cancel() { + } + }); + + assertEquals(Long.MAX_VALUE, requested.get()); + ref.get().onComplete(); + + ts.assertResult(); + } + + @Test + public void disposeNoNeedForReset() { + PublishProcessor pp = PublishProcessor.create(); + + ConnectableFlowable cf = pp.replay(); + + TestSubscriber ts = cf.test(); + + Disposable d = cf.connect(); + + pp.onNext(1); + + d.dispose(); + + ts = cf.test(); + + ts.assertEmpty(); + + cf.connect(); + + ts.assertEmpty(); + + pp.onNext(2); + + ts.assertValuesOnly(2); + } + + @Test + public void disposeNoNeedForResetSizeBound() { + PublishProcessor pp = PublishProcessor.create(); + + ConnectableFlowable cf = pp.replay(10); + + TestSubscriber ts = cf.test(); + + Disposable d = cf.connect(); + + pp.onNext(1); + + d.dispose(); + + ts = cf.test(); + + ts.assertEmpty(); + + cf.connect(); + + ts.assertEmpty(); + + pp.onNext(2); + + ts.assertValuesOnly(2); + } + + @Test + public void disposeNoNeedForResetTimeBound() { + PublishProcessor pp = PublishProcessor.create(); + + ConnectableFlowable cf = pp.replay(10, TimeUnit.MINUTES); + + TestSubscriber ts = cf.test(); + + Disposable d = cf.connect(); + + pp.onNext(1); + + d.dispose(); + + ts = cf.test(); + + ts.assertEmpty(); + + cf.connect(); + + ts.assertEmpty(); + + pp.onNext(2); + + ts.assertValuesOnly(2); + } + + @Test + public void disposeNoNeedForResetTimeAndSIzeBound() { + PublishProcessor pp = PublishProcessor.create(); + + ConnectableFlowable cf = pp.replay(10, 10, TimeUnit.MINUTES); + + TestSubscriber ts = cf.test(); + + Disposable d = cf.connect(); + + pp.onNext(1); + + d.dispose(); + + ts = cf.test(); + + ts.assertEmpty(); + + cf.connect(); + + ts.assertEmpty(); + + pp.onNext(2); + + ts.assertValuesOnly(2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryTest.java index 607801bd195..224ae32d405 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -621,7 +621,7 @@ public void run() { } } - /** Observer for listener on seperate thread. */ + /** Observer for listener on separate thread. */ static final class AsyncSubscriber extends DefaultSubscriber { protected CountDownLatch latch = new CountDownLatch(1); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryWithPredicateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryWithPredicateTest.java index b70b7422018..2180ac88736 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryWithPredicateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableRetryWithPredicateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSampleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSampleTest.java index f9ed6509dbc..1bc6456695b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSampleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSampleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -481,4 +481,10 @@ public void badRequest() { TestHelper.assertBadRequestReported(PublishProcessor.create() .sample(PublishProcessor.create())); } + + @Test + public void badRequestTimed() { + TestHelper.assertBadRequestReported(PublishProcessor.create() + .sample(1, TimeUnit.MINUTES)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScalarXMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScalarXMapTest.java index a4abfce00c5..fab387470e7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScalarXMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScalarXMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -243,4 +243,12 @@ public void cancelled() { assertTrue(scalar.isCancelled()); } + + @Test + public void mapToNonScalar() { + Flowable.fromCallable(() -> 1) + .concatMap(v -> Flowable.range(1, 5)) + .test() + .assertResult(1, 2, 3, 4, 5); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScanTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScanTest.java index 2988da75700..5c6e4fa9013 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScanTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableScanTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -676,4 +676,27 @@ public Integer apply(Integer a, Integer b) throws Exception { } } } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().scanWith(() -> 1, (a, b) -> a + b)); + } + + @Test + public void drainMoreWork() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = pp.scanWith(() -> 0, (a, b) -> a + b) + .doOnNext(v -> { + if (v == 1) { + pp.onNext(2); + pp.onComplete(); + } + }) + .test(); + + pp.onNext(1); + + ts.assertResult(0, 1, 3); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSequenceEqualTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSequenceEqualTest.java index e5e74e8227a..c73b57777be 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSequenceEqualTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSequenceEqualTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -591,4 +591,26 @@ public Flowable apply(Flowable upstream) { } }); } + + @Test + public void fusionRejected() { + Flowable.sequenceEqual(TestHelper.rejectFlowableFusion(), Flowable.never()) + .test() + .assertEmpty(); + } + + @Test + public void fusionRejectedFlowable() { + Flowable.sequenceEqual(TestHelper.rejectFlowableFusion(), Flowable.never()) + .toFlowable() + .test() + .assertEmpty(); + } + + @Test + public void asyncSourceCompare() { + Flowable.sequenceEqual(Flowable.fromCallable(() -> 1), Flowable.just(1)) + .test() + .assertResult(true); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSerializeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSerializeTest.java index cd848e683d8..913c598126d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSerializeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSerializeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -79,7 +79,22 @@ public void multiThreadedBasic() { } @Test - public void multiThreadedWithNPE() { + public void multiThreadedWithNPEFlaky() throws InterruptedException { + int max = 9; + for (int i = 0; i <= max; i++) { + try { + multiThreadedWithNPE(); + return; + } catch (AssertionError ex) { + if (i == max) { + throw ex; + } + } + Thread.sleep((long)(1000 * Math.random() + 100)); + } + } + + void multiThreadedWithNPE() { TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable("one", "two", "three", null); Flowable w = Flowable.unsafeCreate(onSubscribe); @@ -108,7 +123,22 @@ public void multiThreadedWithNPE() { } @Test - public void multiThreadedWithNPEinMiddle() { + public void multiThreadedWithNPEinMiddleFlaky() throws InterruptedException { + int max = 9; + for (int i = 0; i <= max; i++) { + try { + multiThreadedWithNPEinMiddle(); + return; + } catch (AssertionError ex) { + if (i == max) { + throw ex; + } + } + Thread.sleep((long)(1000 * Math.random() + 100)); + } + } + + void multiThreadedWithNPEinMiddle() { boolean lessThan9 = false; for (int i = 0; i < 3; i++) { TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable("one", "two", "three", null, "four", "five", "six", "seven", "eight", "nine"); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingleTest.java index 099f63f0495..85fbfbc00d0 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -805,4 +805,9 @@ public void singleOrError() { .test() .assertFailure(NoSuchElementException.class); } + + @Test + public void dispose() { + TestHelper.checkDisposed(PublishProcessor.create().single(1)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLastTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLastTest.java index 53e4e24a930..69eac72c541 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLastTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLastTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -97,7 +97,7 @@ public void skipLastWithBackpressure() { } - @Test(expected = IndexOutOfBoundsException.class) + @Test(expected = IllegalArgumentException.class) public void skipLastWithNegativeCount() { Flowable.just("one").skipLast(-1); } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLastTimedTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLastTimedTest.java index 87f4ddf881a..f2f1ff25981 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLastTimedTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipLastTimedTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -250,4 +250,27 @@ public void observeOn() { .assertComplete() .assertNoErrors(); } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().skipLast(1, TimeUnit.MINUTES)); + } + + @Test + public void delayErrorMoreWork() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = pp.skipLast(0, TimeUnit.MILLISECONDS, true) + .doOnNext(v -> { + if (v == 1) { + pp.onNext(1); + pp.onComplete(); + } + }) + .test(); + + pp.onNext(1); + + ts.assertComplete(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipTest.java index deb672124a5..eac3c94df83 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -31,7 +31,7 @@ public class FlowableSkipTest extends RxJavaTest { - @Test + @Test(expected = IllegalArgumentException.class) public void skipNegativeElements() { Flowable skip = Flowable.just("one", "two", "three").skip(-99); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipTimedTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipTimedTest.java index 74532ad63ca..82012097e74 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipTimedTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipTimedTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipUntilTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipUntilTest.java index b579f0e5d6c..d5bbdf969a3 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipUntilTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipUntilTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipWhileTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipWhileTest.java index 3ab4f9af640..3fd42350d21 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipWhileTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSkipWhileTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableStartWithTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableStartWithTest.java new file mode 100644 index 00000000000..6aa442c00b5 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableStartWithTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.flowable; + +import static org.mockito.Mockito.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; + +public class FlowableStartWithTest { + + @Test + public void justCompletableComplete() { + Flowable.just(1).startWith(Completable.complete()) + .test() + .assertResult(1); + } + + @Test + public void emptyCompletableComplete() { + Flowable.empty().startWith(Completable.complete()) + .test() + .assertResult(); + } + + @Test + public void runCompletableError() { + Runnable run = mock(Runnable.class); + + Flowable.fromRunnable(run).startWith(Completable.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } + + @Test + public void justSingleJust() { + Flowable.just(1).startWith(Single.just(2)) + .test() + .assertResult(2, 1); + } + + @Test + public void emptySingleJust() { + Runnable run = mock(Runnable.class); + + Flowable.fromRunnable(run) + .startWith(Single.just(2)) + .test() + .assertResult(2); + + verify(run).run(); + } + + @Test + public void runSingleError() { + Runnable run = mock(Runnable.class); + + Flowable.fromRunnable(run).startWith(Single.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } + + @Test + public void justMaybeJust() { + Flowable.just(1).startWith(Maybe.just(2)) + .test() + .assertResult(2, 1); + } + + @Test + public void emptyMaybeJust() { + Runnable run = mock(Runnable.class); + + Flowable.fromRunnable(run) + .startWith(Maybe.just(2)) + .test() + .assertResult(2); + + verify(run).run(); + } + + @Test + public void runMaybeError() { + Runnable run = mock(Runnable.class); + + Flowable.fromRunnable(run).startWith(Maybe.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } + + @Test + public void justFlowableJust() { + Flowable.just(1).startWith(Flowable.just(2, 3, 4, 5)) + .test() + .assertResult(2, 3, 4, 5, 1); + } + + @Test + public void emptyFlowableJust() { + Runnable run = mock(Runnable.class); + + Flowable.fromRunnable(run) + .startWith(Flowable.just(2, 3, 4, 5)) + .test() + .assertResult(2, 3, 4, 5); + + verify(run).run(); + } + + @Test + public void emptyFlowableEmpty() { + Runnable run = mock(Runnable.class); + Runnable run2 = mock(Runnable.class); + + Flowable.fromRunnable(run) + .startWith(Flowable.fromRunnable(run2)) + .test() + .assertResult(); + + verify(run).run(); + verify(run2).run(); + } + + @Test + public void runFlowableError() { + Runnable run = mock(Runnable.class); + + Flowable.fromRunnable(run).startWith(Flowable.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOnTest.java index a9f66d733eb..01ee614fd52 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSubscribeOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,6 +27,7 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.internal.operators.flowable.FlowableSubscribeOn.SubscribeOnSubscriber; +import io.reactivex.rxjava3.internal.schedulers.ImmediateThinScheduler; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.schedulers.*; import io.reactivex.rxjava3.subscribers.*; @@ -201,7 +202,7 @@ public void onNext(Integer t) { System.out.println("First schedule: " + t); assertTrue(t.getName().startsWith("Rx")); ts.request(10); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(20, TimeUnit.SECONDS); System.out.println("After reschedule: " + ts.lastThread()); assertEquals(t, ts.lastThread()); } @@ -253,7 +254,7 @@ public void onNext(Integer t) { } }).subscribeOn(Schedulers.newThread()).subscribe(ts); - ts.awaitDone(5, TimeUnit.SECONDS); + ts.awaitDone(20, TimeUnit.SECONDS); ts.assertNoErrors(); } @@ -329,7 +330,7 @@ public void subscribe(FlowableEmitter s) throws Exception { .subscribeOn(Schedulers.single()) .observeOn(Schedulers.computation()) .test() - .awaitDone(5, TimeUnit.SECONDS) + .awaitDone(20, TimeUnit.SECONDS) .assertNoErrors() .assertComplete(); @@ -354,7 +355,7 @@ public void subscribe(FlowableEmitter s) throws Exception { .subscribeOn(Schedulers.single()) .observeOn(Schedulers.computation()) .test() - .awaitDone(5, TimeUnit.SECONDS) + .awaitDone(20, TimeUnit.SECONDS) .assertValueCount(Flowable.bufferSize()) .assertNoErrors() .assertComplete(); @@ -376,7 +377,7 @@ public void subscribe(FlowableEmitter s) throws Exception { .subscribeOn(Schedulers.single(), false) .observeOn(Schedulers.computation()) .test() - .awaitDone(5, TimeUnit.SECONDS) + .awaitDone(20, TimeUnit.SECONDS) .assertNoErrors() .assertComplete(); @@ -401,9 +402,14 @@ public void subscribe(FlowableEmitter s) throws Exception { .subscribeOn(Schedulers.single(), true) .observeOn(Schedulers.computation()) .test() - .awaitDone(5, TimeUnit.SECONDS) + .awaitDone(20, TimeUnit.SECONDS) .assertValueCount(Flowable.bufferSize()) .assertNoErrors() .assertComplete(); } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().subscribeOn(ImmediateThinScheduler.INSTANCE)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchIfEmptyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchIfEmptyTest.java index de348ee6a0f..d38a657b992 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchIfEmptyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchIfEmptyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchTest.java index fb571c11092..9f200e3c566 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableSwitchTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,7 +19,7 @@ import java.util.*; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.*; import org.junit.*; import org.mockito.InOrder; @@ -32,7 +32,7 @@ import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.internal.util.ExceptionHelper; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.*; import io.reactivex.rxjava3.subscribers.*; import io.reactivex.rxjava3.testsupport.*; @@ -1076,7 +1076,7 @@ protected void subscribeActual(Subscriber s) { } }), 8) .test(1L) - .assertFailure(MissingBackpressureException.class, 0); + .assertFailure(QueueOverflowException.class, 0); } @Test @@ -1229,4 +1229,167 @@ public Publisher apply(Integer v) .test() .assertResult(10, 20); } + + @Test + public void asyncFusedInner() { + Flowable.just(1) + .hide() + .switchMap(v -> Flowable.fromCallable(() -> 1)) + .test() + .assertResult(1); + } + + @Test + public void innerIgnoresCancelAndErrors() throws Throwable { + TestHelper.withErrorTracking(errors -> { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = pp + .switchMap(v -> { + if (v == 1) { + return Flowable.unsafeCreate(s -> { + s.onSubscribe(new BooleanSubscription()); + pp.onNext(2); + s.onError(new TestException()); + }); + } + return Flowable.never(); + }) + .test(); + + pp.onNext(1); + + ts.assertEmpty(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.switchMap(v -> Flowable.never())); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().switchMap(v -> Flowable.never())); + } + + @Test + public void innerFailed() { + BehaviorProcessor.createDefault(Flowable.error(new TestException())) + .switchMap(v -> v) + .test() + .assertFailure(TestException.class) + ; + } + + @Test + public void innerCompleted() { + BehaviorProcessor.createDefault(Flowable.empty().hide()) + .switchMap(v -> v) + .test() + .assertEmpty() + ; + } + + @Test + public void innerCompletedBackpressureBoundary() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = BehaviorProcessor.createDefault(pp) + .onBackpressureBuffer() + .switchMap(v -> v) + .test(1L) + ; + + ts.assertEmpty(); + + pp.onNext(1); + pp.onComplete(); + + ts.assertValuesOnly(1); + } + + @Test + public void innerCompletedDelayError() { + BehaviorProcessor.createDefault(Flowable.empty().hide()) + .switchMapDelayError(v -> v) + .test() + .assertEmpty() + ; + } + + @Test + public void innerCompletedBackpressureBoundaryDelayError() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = BehaviorProcessor.createDefault(pp) + .onBackpressureBuffer() + .switchMapDelayError(v -> v) + .test(1L) + ; + + ts.assertEmpty(); + + pp.onNext(1); + pp.onComplete(); + + ts.assertValuesOnly(1); + } + + @Test + public void cancellationShouldTriggerInnerCancellationRace() throws Throwable { + AtomicInteger outer = new AtomicInteger(); + AtomicInteger inner = new AtomicInteger(); + + int n = 10_000; + for (int i = 0; i < n; i++) { + Flowable.create(it -> { + it.onNext(0); + }, BackpressureStrategy.MISSING) + .switchMap(v -> createFlowable(inner)) + .observeOn(Schedulers.computation()) + .doFinally(() -> { + outer.incrementAndGet(); + }) + .take(1) + .blockingSubscribe(v -> { }, Throwable::printStackTrace); + } + + Thread.sleep(100); + assertEquals(inner.get(), outer.get()); + assertEquals(n, inner.get()); + } + + Flowable createFlowable(AtomicInteger inner) { + return Flowable.unsafeCreate(s -> { + SerializedSubscriber it = new SerializedSubscriber<>(s); + it.onSubscribe(new BooleanSubscription()); + Schedulers.io().scheduleDirect(() -> { + it.onNext(1); + }, 0, TimeUnit.MILLISECONDS); + Schedulers.io().scheduleDirect(() -> { + it.onNext(2); + }, 0, TimeUnit.MILLISECONDS); + }) + .doFinally(() -> { + inner.incrementAndGet(); + }); + } + + @Test + public void innerOnSubscribeOuterCancelRace() { + TestSubscriber ts = new TestSubscriber(); + + Flowable.just(1) + .hide() + .switchMap(v -> Flowable.just(1) + .doOnSubscribe(d -> ts.cancel()) + .scan(1, (a, b) -> a) + ) + .subscribe(ts); + + ts.assertEmpty(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastOneTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastOneTest.java index 373fe4fbe47..1e51a402499 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastOneTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastOneTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastTest.java index c62ff85db04..6008461ed5b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,8 +23,9 @@ import org.junit.Test; import org.mockito.InOrder; -import org.reactivestreams.Subscriber; +import org.reactivestreams.*; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; @@ -89,7 +90,7 @@ public void takeLastWithZeroCount() { verify(subscriber, times(1)).onComplete(); } - @Test(expected = IndexOutOfBoundsException.class) + @Test(expected = IllegalArgumentException.class) public void takeLastWithNegativeCount() { Flowable.just("one").takeLast(-1); } @@ -340,4 +341,54 @@ public void takeLastTake() { .test() .assertResult(6, 7); } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().takeLast(2)); + } + + @Test + public void cancelThenRequest() { + Flowable.never().takeLast(2) + .subscribe(new FlowableSubscriber() { + + @Override + public void onNext(@NonNull Object t) { + } + + @Override + public void onError(Throwable t) { + } + + @Override + public void onComplete() { + } + + @Override + public void onSubscribe(@NonNull Subscription s) { + s.cancel(); + s.request(1); + } + }); + } + + @Test + public void noRequestEmpty() { + Flowable.empty() + .takeLast(2) + .test(0L) + .assertResult(); + } + + @Test + public void moreValuesRemainingThanRequested() { + Flowable.range(1, 4) + .takeLast(3) + .test(0L) + .assertEmpty() + .requestMore(2) + .assertValuesOnly(2, 3) + .requestMore(2) + .assertResult(2, 3, 4); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastTimedTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastTimedTest.java index 3f8c22a47f0..83814dd797b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastTimedTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeLastTimedTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -32,7 +32,7 @@ public class FlowableTakeLastTimedTest extends RxJavaTest { - @Test(expected = IndexOutOfBoundsException.class) + @Test(expected = IllegalArgumentException.class) public void takeLastTimedWithNegativeCount() { Flowable.just("one").takeLast(-1, 1, TimeUnit.SECONDS); } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeTest.java index fa9ea0725d8..50728f62064 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeTest2.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeTest2.java index 089c1480991..da2aa5657e7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeTest2.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeTest2.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeTimedTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeTimedTest.java index 34d39b125af..776236a7cd6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeTimedTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeTimedTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntilPredicateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntilPredicateTest.java index 4019ec4fd90..f88b7e27ae6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntilPredicateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntilPredicateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntilTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntilTest.java index 150143ba6fe..a1f7fe9d42b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntilTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeUntilTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeWhileTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeWhileTest.java index f2c964cf286..805420f094c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeWhileTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTakeWhileTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleFirstTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleFirstTest.java index d26d49019a0..68a559e3cdc 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleFirstTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleFirstTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,6 +19,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; +import io.reactivex.rxjava3.functions.Action; import org.junit.*; import org.mockito.InOrder; import org.reactivestreams.*; @@ -44,6 +45,77 @@ public void before() { subscriber = TestHelper.mockSubscriber(); } + @Test + public void throttlingWithDropCallbackCrashes() throws Throwable { + Flowable source = Flowable.unsafeCreate(new Publisher() { + @Override + public void subscribe(Subscriber subscriber) { + subscriber.onSubscribe(new BooleanSubscription()); + publishNext(subscriber, 100, "one"); // publish as it's first + publishNext(subscriber, 300, "two"); // skip as it's last within the first 400 + publishNext(subscriber, 900, "three"); // publish + publishNext(subscriber, 905, "four"); // skip + publishCompleted(subscriber, 1000); // Should be published as soon as the timeout expires. + } + }); + + Action whenDisposed = mock(Action.class); + + Flowable sampled = source + .doOnCancel(whenDisposed) + .throttleFirst(400, TimeUnit.MILLISECONDS, scheduler, e -> { + if ("two".equals(e)) { + throw new TestException("forced"); + } + }); + sampled.subscribe(subscriber); + + InOrder inOrder = inOrder(subscriber); + + scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); + inOrder.verify(subscriber, times(1)).onNext("one"); + inOrder.verify(subscriber, times(1)).onError(any(TestException.class)); + inOrder.verify(subscriber, times(0)).onNext("two"); + inOrder.verify(subscriber, times(0)).onNext("three"); + inOrder.verify(subscriber, times(0)).onNext("four"); + inOrder.verify(subscriber, times(0)).onComplete(); + inOrder.verifyNoMoreInteractions(); + verify(whenDisposed).run(); + } + + @Test + public void throttlingWithDropCallback() { + Flowable source = Flowable.unsafeCreate(new Publisher() { + @Override + public void subscribe(Subscriber subscriber) { + subscriber.onSubscribe(new BooleanSubscription()); + publishNext(subscriber, 100, "one"); // publish as it's first + publishNext(subscriber, 300, "two"); // skip as it's last within the first 400 + publishNext(subscriber, 900, "three"); // publish + publishNext(subscriber, 905, "four"); // skip + publishCompleted(subscriber, 1000); // Should be published as soon as the timeout expires. + } + }); + + Observer dropCallbackObserver = TestHelper.mockObserver(); + Flowable sampled = source.throttleFirst(400, TimeUnit.MILLISECONDS, scheduler, dropCallbackObserver::onNext); + sampled.subscribe(subscriber); + + InOrder inOrder = inOrder(subscriber); + InOrder dropCallbackOrder = inOrder(dropCallbackObserver); + + scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); + inOrder.verify(subscriber, times(1)).onNext("one"); + inOrder.verify(subscriber, times(0)).onNext("two"); + dropCallbackOrder.verify(dropCallbackObserver, times(1)).onNext("two"); + inOrder.verify(subscriber, times(1)).onNext("three"); + inOrder.verify(subscriber, times(0)).onNext("four"); + dropCallbackOrder.verify(dropCallbackObserver, times(1)).onNext("four"); + inOrder.verify(subscriber, times(1)).onComplete(); + inOrder.verifyNoMoreInteractions(); + dropCallbackOrder.verifyNoMoreInteractions(); + } + @Test public void throttlingWithCompleted() { Flowable source = Flowable.unsafeCreate(new Publisher() { @@ -200,4 +272,14 @@ public void backpressureNoRequest() { .test(0L) .assertFailure(MissingBackpressureException.class); } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().throttleFirst(1, TimeUnit.MINUTES)); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.throttleFirst(1, TimeUnit.MINUTES)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleLatestTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleLatestTest.java index 45457f55778..2b26ec98d41 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleLatestTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableThrottleLatestTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,10 +23,11 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.subscriptions.EmptySubscription; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.schedulers.TestScheduler; import io.reactivex.rxjava3.subscribers.TestSubscriber; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class FlowableThrottleLatestTest extends RxJavaTest { @@ -278,4 +279,480 @@ public void onNext(Integer t) { ts.assertResult(1, 2); } + + /** Emit 1, 2, 3, then advance time by a second; 1 and 3 should end up in downstream, 2 should be dropped. */ + @Test + public void onDroppedBasicNoEmitLast() { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + TestSubscriber drops = new TestSubscriber<>(); + drops.onSubscribe(EmptySubscription.INSTANCE); + + TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .test(); + + ts.assertEmpty(); + drops.assertEmpty(); + + pp.onNext(1); + + ts.assertValuesOnly(1); + drops.assertEmpty(); + + pp.onNext(2); + + ts.assertValuesOnly(1); + drops.assertEmpty(); + + pp.onNext(3); + + ts.assertValuesOnly(1); + drops.assertValuesOnly(2); + + sch.advanceTimeBy(1, TimeUnit.SECONDS); + + ts.assertValuesOnly(1, 3); + drops.assertValuesOnly(2); + + pp.onComplete(); + + ts.assertResult(1, 3); + + drops.assertValuesOnly(2); + } + + /** Emit 1, 2, 3; 1 should end up in downstream, 2, 3 should be dropped. */ + @Test + public void onDroppedBasicNoEmitLastDropLast() { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + TestSubscriber drops = new TestSubscriber<>(); + drops.onSubscribe(EmptySubscription.INSTANCE); + + TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .test(); + + ts.assertEmpty(); + drops.assertEmpty(); + + pp.onNext(1); + + ts.assertValuesOnly(1); + drops.assertEmpty(); + + pp.onNext(2); + + ts.assertValuesOnly(1); + drops.assertEmpty(); + + pp.onNext(3); + + ts.assertValuesOnly(1); + drops.assertValuesOnly(2); + + pp.onComplete(); + + ts.assertResult(1); + + drops.assertValuesOnly(2, 3); + } + + /** Emit 1, 2, 3; 1 and 3 should end up in downstream, 2 should be dropped. */ + @Test + public void onDroppedBasicEmitLast() { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + TestSubscriber drops = new TestSubscriber<>(); + drops.onSubscribe(EmptySubscription.INSTANCE); + + TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, true, drops::onNext) + .test(); + + ts.assertEmpty(); + drops.assertEmpty(); + + pp.onNext(1); + + ts.assertValuesOnly(1); + drops.assertEmpty(); + + pp.onNext(2); + + ts.assertValuesOnly(1); + drops.assertEmpty(); + + pp.onNext(3); + + ts.assertValuesOnly(1); + drops.assertValuesOnly(2); + + pp.onComplete(); + + ts.assertResult(1, 3); + + drops.assertValuesOnly(2); + } + + /** Emit 1, 2, 3; 3 should trigger an error to the downstream because 2 is dropped and the callback crashes. */ + @Test + public void onDroppedBasicNoEmitLastFirstDropCrash() throws Throwable { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestSubscriber ts = pp + .doOnCancel(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { + if (d == 2) { + throw new TestException("forced"); + } + }) + .test(); + + ts.assertEmpty(); + + pp.onNext(1); + + ts.assertValuesOnly(1); + + pp.onNext(2); + + ts.assertValuesOnly(1); + + pp.onNext(3); + + ts.assertFailure(TestException.class, 1); + + verify(whenDisposed).run(); + } + + /** + * Emit 1, 2, Error; the error should trigger the drop callback and crash it too, + * downstream gets 1, composite(source, drop-crash). + */ + @Test + public void onDroppedBasicNoEmitLastOnErrorDropCrash() throws Throwable { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestSubscriberEx ts = pp + .doOnCancel(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .subscribeWith(new TestSubscriberEx<>()); + + ts.assertEmpty(); + + pp.onNext(1); + + ts.assertValuesOnly(1); + + pp.onNext(2); + + ts.assertValuesOnly(1); + + pp.onError(new TestException("source")); + + ts.assertFailure(CompositeException.class, 1); + + TestHelper.assertCompositeExceptions(ts, TestException.class, "source", TestException.class, "forced 2"); + + verify(whenDisposed, never()).run(); + } + + /** + * Emit 1, 2, 3; 3 should trigger a drop-crash for 2, which then would trigger the error path and drop-crash for 3, + * the last item not delivered, downstream gets 1, composite(drop-crash 2, drop-crash 3). + */ + @Test + public void onDroppedBasicEmitLastOnErrorDropCrash() throws Throwable { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestSubscriberEx ts = pp + .doOnCancel(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, true, d -> { throw new TestException("forced " + d); }) + .subscribeWith(new TestSubscriberEx<>()); + + ts.assertEmpty(); + + pp.onNext(1); + + ts.assertValuesOnly(1); + + pp.onNext(2); + + ts.assertValuesOnly(1); + + pp.onNext(3); + + ts.assertFailure(CompositeException.class, 1); + + TestHelper.assertCompositeExceptions(ts, TestException.class, "forced 2", TestException.class, "forced 3"); + + verify(whenDisposed).run(); + } + + /** Emit 1, complete; Downstream gets 1, complete, no drops. */ + @Test + public void onDroppedBasicNoEmitLastNoLastToDrop() { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + TestSubscriber drops = new TestSubscriber<>(); + drops.onSubscribe(EmptySubscription.INSTANCE); + + TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .test(); + + ts.assertEmpty(); + drops.assertEmpty(); + + pp.onNext(1); + + ts.assertValuesOnly(1); + drops.assertEmpty(); + + pp.onComplete(); + + ts.assertResult(1); + drops.assertEmpty(); + } + + /** Emit 1, error; Downstream gets 1, error, no drops. */ + @Test + public void onDroppedErrorNoEmitLastNoLastToDrop() { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + TestSubscriber drops = new TestSubscriber<>(); + drops.onSubscribe(EmptySubscription.INSTANCE); + + TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .test(); + + ts.assertEmpty(); + drops.assertEmpty(); + + pp.onNext(1); + + ts.assertValuesOnly(1); + drops.assertEmpty(); + + pp.onError(new TestException()); + + ts.assertFailure(TestException.class, 1); + drops.assertEmpty(); + } + + /** + * Emit 1, 2, complete; complete should crash drop, downstream gets 1, drop-crash 2. + */ + @Test + public void onDroppedHasLastNoEmitLastDropCrash() throws Throwable { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestSubscriberEx ts = pp + .doOnCancel(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .subscribeWith(new TestSubscriberEx<>()); + + ts.assertEmpty(); + + pp.onNext(1); + + ts.assertValuesOnly(1); + + pp.onNext(2); + + ts.assertValuesOnly(1); + + pp.onComplete(); + + ts.assertFailureAndMessage(TestException.class, "forced 2", 1); + + verify(whenDisposed, never()).run(); + } + + /** + * Emit 1, 2 then dispose the sequence; downstream gets 1, drop should get for 2. + */ + @Test + public void onDroppedDisposeDrops() throws Throwable { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestSubscriber drops = new TestSubscriber<>(); + drops.onSubscribe(EmptySubscription.INSTANCE); + + TestSubscriberEx ts = pp + .doOnCancel(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .subscribeWith(new TestSubscriberEx<>()); + + ts.assertEmpty(); + + pp.onNext(1); + + ts.assertValuesOnly(1); + + pp.onNext(2); + + ts.assertValuesOnly(1); + + ts.cancel(); + + ts.assertValuesOnly(1); + drops.assertValuesOnly(2); + + verify(whenDisposed).run(); + } + + /** + * Emit 1 then dispose the sequence; downstream gets 1, drop should not get called. + */ + @Test + public void onDroppedDisposeNoDrops() throws Throwable { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestSubscriber drops = new TestSubscriber<>(); + drops.onSubscribe(EmptySubscription.INSTANCE); + + TestSubscriberEx ts = pp + .doOnCancel(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .subscribeWith(new TestSubscriberEx<>()); + + ts.assertEmpty(); + + pp.onNext(1); + + ts.assertValuesOnly(1); + + ts.cancel(); + + ts.assertValuesOnly(1); + drops.assertEmpty(); + + verify(whenDisposed).run(); + } + + /** + * Emit 1, 2 then dispose the sequence; downstream gets 1, global error handler should get drop-crash 2. + */ + @Test + public void onDroppedDisposeCrashesDrop() throws Throwable { + TestHelper.withErrorTracking(errors -> { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestSubscriberEx ts = pp + .doOnCancel(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .subscribeWith(new TestSubscriberEx<>()); + + ts.assertEmpty(); + + pp.onNext(1); + + ts.assertValuesOnly(1); + + pp.onNext(2); + + ts.assertValuesOnly(1); + + ts.cancel(); + + ts.assertValuesOnly(1); + + verify(whenDisposed).run(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class, "forced 2"); + }); + } + + /** Emit 1 but downstream is backpressured; downstream gets MBE, drops gets 1. */ + @Test + public void onDroppedBackpressured() throws Throwable { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + TestSubscriber drops = new TestSubscriber<>(); + drops.onSubscribe(EmptySubscription.INSTANCE); + + Action whenDisposed = mock(Action.class); + + TestSubscriber ts = pp + .doOnCancel(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .test(0L); + + ts.assertEmpty(); + drops.assertEmpty(); + + pp.onNext(1); + + ts.assertFailure(MissingBackpressureException.class); + + drops.assertValuesOnly(1); + + verify(whenDisposed).run(); + } + + /** Emit 1 but downstream is backpressured; drop crashes, downstream gets composite(MBE, drop-crash 1). */ + @Test + public void onDroppedBackpressuredDropCrash() throws Throwable { + PublishProcessor pp =PublishProcessor.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestSubscriberEx ts = pp + .doOnCancel(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .subscribeWith(new TestSubscriberEx<>(0L)); + + ts.assertEmpty(); + + pp.onNext(1); + + ts.assertFailure(CompositeException.class); + + TestHelper.assertCompositeExceptions(ts, + MissingBackpressureException.class, "Could not emit value due to lack of requests", + TestException.class, "forced 1"); + + verify(whenDisposed).run(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeIntervalTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeIntervalTest.java index 4153c92a222..e2e9550388d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeIntervalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeIntervalTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeoutTests.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeoutTests.java index 88a3bc22531..070bb620b01 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeoutTests.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeoutTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,7 +30,7 @@ import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; -import io.reactivex.rxjava3.schedulers.TestScheduler; +import io.reactivex.rxjava3.schedulers.*; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; @@ -528,4 +528,9 @@ public void run() { } } } + + @Test + public void doubleOnSubscribeFallback() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.timeout(1, TimeUnit.MINUTES, Flowable.never())); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeoutWithSelectorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeoutWithSelectorTest.java index 7e55fa0d773..538a8e566a4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeoutWithSelectorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimeoutWithSelectorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -32,6 +32,7 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.internal.operators.flowable.FlowableTimeout.TimeoutConsumer; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.*; @@ -894,4 +895,13 @@ protected void subscribeActual(Subscriber s) { RxJavaPlugins.reset(); } } + + @Test + public void timeoutConsumerIsDisposed() { + TimeoutConsumer consumer = new TimeoutConsumer(0, null); + + assertFalse(consumer.isDisposed()); + consumer.dispose(); + assertTrue(consumer.isDisposed()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimerTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimerTest.java index e23228f9433..4f0216e6121 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimerTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -352,7 +352,7 @@ public void timerDelayZero() { public void timerInterruptible() throws Exception { ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); try { - for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec) }) { + for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec, true) }) { final AtomicBoolean interrupted = new AtomicBoolean(); TestSubscriber ts = Flowable.timer(1, TimeUnit.MILLISECONDS, s) .map(new Function() { @@ -380,4 +380,9 @@ public Long apply(Long v) throws Exception { exec.shutdown(); } } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.timer(1, TimeUnit.MINUTES)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimestampTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimestampTest.java index 05274da6190..6d98c0c4140 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimestampTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableTimestampTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToCompletableTest.java index cac1fa61b7e..dff5a7462ba 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToCompletableTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.flowable; import static org.junit.Assert.assertFalse; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToFutureTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToFutureTest.java index 524a7216e11..8501a22e74a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToFutureTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToFutureTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -62,7 +62,7 @@ public void successOperatesOnSuppliedScheduler() throws Exception { TestScheduler scheduler = new TestScheduler(); TestSubscriber ts = new TestSubscriber<>(subscriber); - Flowable.fromFuture(future, scheduler).subscribe(ts); + Flowable.fromFuture(future).subscribeOn(scheduler).subscribe(ts); verify(subscriber, never()).onNext(value); @@ -234,7 +234,7 @@ public void run() { TestSubscriber ts = TestSubscriber.create(); - Flowable.fromFuture(task, Schedulers.computation()).subscribe(ts); + Flowable.fromFuture(task).subscribeOn(Schedulers.computation()).subscribe(ts); task.run(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToListTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToListTest.java index cad29e3fc88..208f371bb77 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToListTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToListTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToMapTest.java index 149a3f893c4..736cf4caa51 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToMultimapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToMultimapTest.java index 06e71d6beb3..63db446ee69 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToMultimapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToMultimapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToSingleTest.java index b88824b583a..d064589b1d8 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToSortedListTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToSortedListTest.java index 5c7278da545..cadcb572b61 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToSortedListTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableToSortedListTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUnsubscribeOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUnsubscribeOnTest.java index 1f37dbddce8..2a8efa4593c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUnsubscribeOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUnsubscribeOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,6 +26,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Action; +import io.reactivex.rxjava3.internal.schedulers.ImmediateThinScheduler; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.Schedulers; @@ -274,4 +275,9 @@ protected void subscribeActual(Subscriber subscriber) { RxJavaPlugins.reset(); } } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.unsubscribeOn(ImmediateThinScheduler.INSTANCE)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUsingTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUsingTest.java index f32b599df44..d744c327475 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUsingTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableUsingTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithFlowableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithFlowableTest.java index 66273656f94..5f5d97af1e0 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithFlowableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithFlowableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -623,6 +623,7 @@ public void run() { } @Test + @SuppressUndeliverable public void disposeMainBoundaryErrorRace() { final TestException ex = new TestException(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithSizeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithSizeTest.java index fbefcc953e3..bd50a20a2a4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithSizeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithSizeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -25,6 +25,7 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; @@ -605,4 +606,210 @@ public void accept(Flowable v) throws Throwable { inner.get().test().assertResult(1); } + + @Test + public void badRequestExact() { + TestHelper.assertBadRequestReported(Flowable.never().window(1)); + } + + @Test + public void badRequestSkip() { + TestHelper.assertBadRequestReported(Flowable.never().window(1, 2)); + } + + @Test + public void badRequestOverlap() { + TestHelper.assertBadRequestReported(Flowable.never().window(2, 1)); + } + + @Test + public void skipEmpty() { + Flowable.empty() + .window(1, 2) + .test() + .assertResult(); + } + + @Test + public void exactEmpty() { + Flowable.empty() + .window(2) + .test() + .assertResult(); + } + + @Test + public void skipMultipleRequests() { + Flowable.range(1, 10) + .window(1, 2) + .doOnNext(w -> w.test()) + .rebatchRequests(1) + .test() + .assertComplete(); + } + + @Test + public void skipOne() { + Flowable.just(1) + .window(2, 3) + .flatMap(v -> v) + .test() + .assertResult(1); + } + + @Test + public void overlapMultipleRequests() { + Flowable.range(1, 10) + .window(2, 1) + .doOnNext(w -> w.test()) + .rebatchRequests(1) + .test() + .assertComplete(); + } + + @Test + public void overlapCancelAfterWindow() { + Flowable.range(1, 10) + .window(2, 1) + .takeUntil(v -> true) + .doOnNext(w -> w.test()) + .test(0L) + .requestMore(10) + .assertComplete(); + } + + @Test + public void overlapEmpty() { + Flowable.empty() + .window(2, 1) + .test() + .assertResult(); + } + + @Test + public void overlapEmptyNoRequest() { + Flowable.empty() + .window(2, 1) + .test(0L) + .assertResult(); + } + + @Test + public void overlapMoreWorkAfterOnNext() { + PublishProcessor pp = PublishProcessor.create(); + AtomicBoolean once = new AtomicBoolean(); + + TestSubscriber> ts = pp.window(2, 1) + .doOnNext(v -> { + v.test(); + if (once.compareAndSet(false, true)) { + pp.onNext(2); + pp.onComplete(); + } + }) + .test(); + + pp.onNext(1); + + ts.assertComplete(); + } + + @Test + public void moreQueuedClean() { + Flowable.range(1, 10) + .window(5, 1) + .doOnNext(w -> w.test()) + .test(3) + .cancel(); + } + + @Test + public void cancelWithoutWindowSize() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber> ts = pp.window(10) + .test(); + + assertTrue(pp.hasSubscribers()); + + ts.cancel(); + + assertFalse("Subject still has subscribers!", pp.hasSubscribers()); + } + + @Test + public void cancelAfterAbandonmentSize() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber> ts = pp.window(10) + .test(); + + assertTrue(pp.hasSubscribers()); + + pp.onNext(1); + + ts.cancel(); + + assertFalse("Subject still has subscribers!", pp.hasSubscribers()); + } + + @Test + public void cancelWithoutWindowSkip() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber> ts = pp.window(10, 15) + .test(); + + assertTrue(pp.hasSubscribers()); + + ts.cancel(); + + assertFalse("Subject still has subscribers!", pp.hasSubscribers()); + } + + @Test + public void cancelAfterAbandonmentSkip() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber> ts = pp.window(10, 15) + .test(); + + assertTrue(pp.hasSubscribers()); + + pp.onNext(1); + + ts.cancel(); + + assertFalse("Subject still has subscribers!", pp.hasSubscribers()); + } + + @Test + public void cancelWithoutWindowOverlap() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber> ts = pp.window(10, 5) + .test(); + + assertTrue(pp.hasSubscribers()); + + ts.cancel(); + + assertFalse("Subject still has subscribers!", pp.hasSubscribers()); + } + + @Test + public void cancelAfterAbandonmentOverlap() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber> ts = pp.window(10, 5) + .test(); + + assertTrue(pp.hasSubscribers()); + + pp.onNext(1); + + ts.cancel(); + + assertFalse("Subject still has subscribers!", pp.hasSubscribers()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithStartEndFlowableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithStartEndFlowableTest.java index 023f6848d58..f2431eb8db9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithStartEndFlowableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithStartEndFlowableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,6 +15,7 @@ import static org.junit.Assert.*; +import java.io.IOException; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.*; @@ -31,7 +32,7 @@ import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.TestScheduler; import io.reactivex.rxjava3.subscribers.*; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class FlowableWindowWithStartEndFlowableTest extends RxJavaTest { @@ -233,20 +234,20 @@ public void dispose() { @Test public void reentrant() { - final FlowableProcessor ps = PublishProcessor.create(); + final FlowableProcessor pp = PublishProcessor.create(); TestSubscriber ts = new TestSubscriber() { @Override public void onNext(Integer t) { super.onNext(t); if (t == 1) { - ps.onNext(2); - ps.onComplete(); + pp.onNext(2); + pp.onComplete(); } } }; - ps.window(BehaviorProcessor.createDefault(1), Functions.justFunction(Flowable.never())) + pp.window(BehaviorProcessor.createDefault(1), Functions.justFunction(Flowable.never())) .flatMap(new Function, Flowable>() { @Override public Flowable apply(Flowable v) throws Exception { @@ -255,7 +256,7 @@ public Flowable apply(Flowable v) throws Exception { }) .subscribe(ts); - ps.onNext(1); + pp.onNext(1); ts .awaitDone(1, TimeUnit.SECONDS) @@ -323,6 +324,7 @@ public Flowable apply(Integer v) throws Exception { } @Test + @SuppressUndeliverable public void endError() { PublishProcessor source = PublishProcessor.create(); PublishProcessor start = PublishProcessor.create(); @@ -539,4 +541,179 @@ public Publisher apply(Integer end) throws Throwable { assertFalse(boundary.hasSubscribers()); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(o -> o.window(Flowable.never(), v -> Flowable.never())); + } + + @Test + public void openError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + TestException ex1 = new TestException(); + TestException ex2 = new TestException(); + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + AtomicReference> ref1 = new AtomicReference<>(); + AtomicReference> ref2 = new AtomicReference<>(); + + Flowable f1 = Flowable.fromPublisher(ref1::set); + Flowable f2 = Flowable.fromPublisher(ref2::set); + + TestSubscriber> ts = BehaviorProcessor.createDefault(1) + .window(f1, v -> f2) + .doOnNext(w -> w.test()) + .test(); + + ref1.get().onSubscribe(new BooleanSubscription()); + ref1.get().onNext(1); + ref2.get().onSubscribe(new BooleanSubscription()); + + TestHelper.race( + () -> ref1.get().onError(ex1), + () -> ref2.get().onError(ex2) + ); + + ts.assertError(RuntimeException.class); + + if (!errors.isEmpty()) { + TestHelper.assertUndeliverable(errors, 0, TestException.class); + } + + errors.clear(); + } + }); + } + + @Test + public void closeError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + AtomicReference> ref1 = new AtomicReference<>(); + AtomicReference> ref2 = new AtomicReference<>(); + + Flowable f1 = Flowable.unsafeCreate(ref1::set); + Flowable f2 = Flowable.unsafeCreate(ref2::set); + + TestSubscriber ts = BehaviorProcessor.createDefault(1) + .window(f1, v -> f2) + .flatMap(v -> v) + .test(); + + ref1.get().onSubscribe(new BooleanSubscription()); + ref1.get().onNext(1); + ref2.get().onSubscribe(new BooleanSubscription()); + + ref2.get().onError(new TestException()); + ref2.get().onError(new TestException()); + + ts.assertFailure(TestException.class); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void upstreamFailsBeforeFirstWindow() { + Flowable.error(new TestException()) + .window(Flowable.never(), v -> Flowable.never()) + .test() + .assertFailure(TestException.class); + } + + @Test + public void windowOpenMainCompletes() { + AtomicReference> ref1 = new AtomicReference<>(); + + PublishProcessor pp = PublishProcessor.create(); + Flowable f1 = Flowable.unsafeCreate(ref1::set); + + AtomicInteger counter = new AtomicInteger(); + + TestSubscriber> ts = pp + .window(f1, v -> Flowable.never()) + .doOnNext(w -> { + if (counter.getAndIncrement() == 0) { + ref1.get().onNext(2); + pp.onNext(1); + pp.onComplete(); + } + w.test(); + }) + .test(); + + ref1.get().onSubscribe(new BooleanSubscription()); + ref1.get().onNext(1); + + ts.assertComplete(); + } + + @Test + public void windowOpenMainError() { + AtomicReference> ref1 = new AtomicReference<>(); + + PublishProcessor pp = PublishProcessor.create(); + Flowable f1 = Flowable.unsafeCreate(ref1::set); + + AtomicInteger counter = new AtomicInteger(); + + TestSubscriber> ts = pp + .window(f1, v -> Flowable.never()) + .doOnNext(w -> { + if (counter.getAndIncrement() == 0) { + ref1.get().onNext(2); + pp.onNext(1); + pp.onError(new TestException()); + } + w.test(); + }) + .test(); + + ref1.get().onSubscribe(new BooleanSubscription()); + ref1.get().onNext(1); + + ts.assertError(TestException.class); + } + + @Test + public void windowOpenIgnoresDispose() { + AtomicReference> ref1 = new AtomicReference<>(); + + PublishProcessor pp = PublishProcessor.create(); + Flowable f1 = Flowable.unsafeCreate(ref1::set); + + TestSubscriber> ts = pp + .window(f1, v -> Flowable.never()) + .take(1) + .doOnNext(w -> { + w.test(); + }) + .test(); + + ref1.get().onSubscribe(new BooleanSubscription()); + ref1.get().onNext(1); + ref1.get().onNext(2); + + ts.assertValueCount(1); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().window(Flowable.never(), v -> Flowable.never())); + } + + @Test + public void mainIgnoresCancelBeforeOnError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Flowable.fromPublisher(s -> { + s.onSubscribe(new BooleanSubscription()); + s.onNext(1); + s.onError(new IOException()); + }) + .window(BehaviorProcessor.createDefault(1), v -> Flowable.error(new TestException())) + .doOnNext(w -> w.test()) + .test() + .assertError(TestException.class); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + }); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithTimeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithTimeTest.java index e3d9466b3e6..6982b00ceac 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithTimeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWindowWithTimeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -31,7 +31,7 @@ import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.*; import io.reactivex.rxjava3.subscribers.*; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class FlowableWindowWithTimeTest extends RxJavaTest { @@ -556,6 +556,7 @@ public void restartTimer() { } @Test + @SuppressUndeliverable public void exactBoundaryError() { Flowable.error(new TestException()) .window(1, TimeUnit.DAYS, Schedulers.single(), 2, true) @@ -973,6 +974,7 @@ public void accept(Flowable v) throws Exception { } @Test + @SuppressUndeliverable public void exactTimeBoundNoInterruptWindowOutputOnError() throws Exception { final AtomicBoolean isInterrupted = new AtomicBoolean(); @@ -1053,6 +1055,7 @@ public void accept(Flowable v) throws Exception { } @Test + @SuppressUndeliverable public void exactTimeAndSizeBoundNoInterruptWindowOutputOnError() throws Exception { final AtomicBoolean isInterrupted = new AtomicBoolean(); @@ -1133,6 +1136,7 @@ public void accept(Flowable v) throws Exception { } @Test + @SuppressUndeliverable public void skipTimeAndSizeBoundNoInterruptWindowOutputOnError() throws Exception { final AtomicBoolean isInterrupted = new AtomicBoolean(); @@ -1321,5 +1325,27 @@ public void accept(Flowable v) throws Throwable { inner.get().test().assertResult(); } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Flowable.never().window(1, TimeUnit.SECONDS)); + } + + @Test + public void timedBoundarySignalAndDisposeRace() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + TestScheduler scheduler = new TestScheduler(); + + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber> ts = pp.window(1, TimeUnit.MINUTES, scheduler, 1) + .test(); + + TestHelper.race( + () -> pp.onNext(1), + () -> ts.cancel() + ); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWithLatestFromTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWithLatestFromTest.java index 655452057b1..df325cd2c81 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWithLatestFromTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableWithLatestFromTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipCompletionTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipCompletionTest.java index 3de4aa1e39f..fe69ea6be52 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipCompletionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipCompletionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipIterableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipIterableTest.java index 871b603383b..aee49596d92 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipIterableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipIterableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipTest.java index 614dc28aaa6..8d3e10dbd27 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/FlowableZipTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,8 +30,8 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueSubscription; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.schedulers.Schedulers; @@ -1870,7 +1870,7 @@ public Integer apply(Integer a, Integer b) throws Exception { public void firstErrorPreventsSecondSubscription() { final AtomicInteger counter = new AtomicInteger(); - List> flowableList = new ArrayList<>(); + List> flowableList = new ArrayList<>(); flowableList.add(Flowable.create(new FlowableOnSubscribe() { @Override public void subscribe(FlowableEmitter e) @@ -1914,4 +1914,30 @@ public Integer apply(Object[] t) throws Throwable { .test() .assertResult(2); } + + @Test + public void fusedInnerPollCrashDelayError() { + Flowable.zip( + Flowable.range(1, 5), + Flowable.just(1) + .map(v -> { throw new TestException(); }) + .compose(TestHelper.flowableStripBoundary()), + (a, b) -> a + b, true + ) + .test() + .assertFailure(TestException.class); + } + + @Test + public void fusedInnerPollCrashRequestBoundaryDelayError() { + Flowable.zip( + Flowable.range(1, 5), + Flowable.just(1) + .map(v -> { throw new TestException(); }) + .compose(TestHelper.flowableStripBoundary()), + (a, b) -> a + b, true + ) + .test(0L) + .assertFailure(TestException.class); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/NotificationLiteTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/NotificationLiteTest.java index 3a5ff0dc570..2c4b42aa9c4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/NotificationLiteTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/flowable/NotificationLiteTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/AbstractMaybeWithUpstreamTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/AbstractMaybeWithUpstreamTest.java index 0e953b262f3..dca854d3c15 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/AbstractMaybeWithUpstreamTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/AbstractMaybeWithUpstreamTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeAmbTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeAmbTest.java index fb3a6aff5b5..54750101639 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeAmbTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeAmbTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeBlockingSubscribeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeBlockingSubscribeTest.java new file mode 100644 index 00000000000..e11548cdc99 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeBlockingSubscribeTest.java @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Maybe; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class MaybeBlockingSubscribeTest { + + @Test + public void noArgSuccess() { + Maybe.just(1) + .blockingSubscribe(); + } + + @Test + public void noArgSuccessAsync() { + Maybe.just(1) + .delay(100, TimeUnit.MILLISECONDS) + .blockingSubscribe(); + } + + @Test + public void noArgEmpty() { + Maybe.empty() + .blockingSubscribe(); + } + + @Test + public void noArgEmptyAsync() { + Maybe.empty() + .delay(100, TimeUnit.MILLISECONDS) + .blockingSubscribe(); + } + + @Test + public void noArgError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Maybe.error(new TestException()) + .blockingSubscribe(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void noArgErrorAsync() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Maybe.error(new TestException()) + .delay(100, TimeUnit.MILLISECONDS, Schedulers.computation()) + .blockingSubscribe(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void oneArgSuccess() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + + Maybe.just(1) + .blockingSubscribe(success); + + verify(success).accept(1); + } + + @Test + public void oneArgSuccessAsync() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + + Maybe.just(1) + .delay(50, TimeUnit.MILLISECONDS) + .blockingSubscribe(success); + + verify(success).accept(1); + } + + @Test + public void oneArgEmpty() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + + Maybe.empty() + .blockingSubscribe(success); + + verify(success, never()).accept(any()); + } + + @Test + public void oneArgEmptyAsync() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + + Maybe.empty() + .delay(50, TimeUnit.MILLISECONDS) + .blockingSubscribe(success); + + verify(success, never()).accept(any()); + } + + @Test + public void oneArgSuccessFails() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + doThrow(new TestException()).when(success).accept(any()); + + Maybe.just(1) + .blockingSubscribe(success); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(success).accept(1); + }); + } + + @Test + public void oneArgError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + + Maybe.error(new TestException()) + .blockingSubscribe(success); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(success, never()).accept(any()); + }); + } + + @Test + public void oneArgErrorAsync() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + + Maybe.error(new TestException()) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation()) + .blockingSubscribe(success); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(success, never()).accept(any()); + }); + } + + @Test + public void twoArgSuccess() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Maybe.just(1) + .blockingSubscribe(success, consumer); + + verify(success).accept(1); + verify(consumer, never()).accept(any()); + } + + @Test + public void twoArgSuccessAsync() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Maybe.just(1) + .delay(50, TimeUnit.MILLISECONDS) + .blockingSubscribe(success, consumer); + + verify(success).accept(any()); + verify(consumer, never()).accept(any()); + } + + @Test + public void twoArgEmpty() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Maybe.empty() + .blockingSubscribe(success, consumer); + + verify(success, never()).accept(any()); + verify(consumer, never()).accept(any()); + } + + @Test + public void twoArgEmptyAsync() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Maybe.empty() + .delay(50, TimeUnit.MILLISECONDS) + .blockingSubscribe(success, consumer); + + verify(success, never()).accept(any()); + verify(consumer, never()).accept(any()); + } + + @Test + public void twoArgSuccessFails() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + doThrow(new TestException()).when(success).accept(any()); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Maybe.just(1) + .blockingSubscribe(success, consumer); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(success).accept(any()); + verify(consumer, never()).accept(any()); + }); + } + + @Test + public void twoArgError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Maybe.error(new TestException()) + .blockingSubscribe(success, consumer); + + assertTrue("" + errors, errors.isEmpty()); + + verify(success, never()).accept(any()); + verify(consumer).accept(any(TestException.class)); + }); + } + + @Test + public void twoArgErrorAsync() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Maybe.error(new TestException()) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation()) + .blockingSubscribe(success, consumer); + + assertTrue("" + errors, errors.isEmpty()); + + verify(success, never()).accept(any()); + verify(consumer).accept(any(TestException.class)); + }); + } + + @Test + public void twoArgErrorFails() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + doThrow(new TestException()).when(consumer).accept(any()); + + Maybe.error(new TestException()) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation()) + .blockingSubscribe(success, consumer); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(success, never()).accept(any()); + verify(consumer).accept(any(TestException.class)); + }); + } + + @Test + public void threeArgSuccess() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + Action action = mock(Action.class); + + Maybe.just(1) + .blockingSubscribe(success, consumer, action); + + verify(success).accept(any()); + verify(consumer, never()).accept(any(Throwable.class)); + verify(action, never()).run(); + } + + @Test + public void threeArgEmpty() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + Action action = mock(Action.class); + + Maybe.empty() + .blockingSubscribe(success, consumer, action); + + verify(success, never()).accept(any()); + verify(consumer, never()).accept(any(Throwable.class)); + verify(action).run(); + } + + @Test + public void threeArgError() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + Action action = mock(Action.class); + + Maybe.error(new TestException()) + .blockingSubscribe(success, consumer, action); + + verify(success, never()).accept(any()); + verify(consumer).accept(any(TestException.class)); + verify(action, never()).run(); + } + + @Test + public void threeArgEmptyFails() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Action action = mock(Action.class); + doThrow(new TestException()).when(action).run(); + + Maybe.empty() + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation()) + .blockingSubscribe(success, consumer, action); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(success, never()).accept(any()); + verify(consumer, never()).accept(any()); + verify(action).run(); + }); + } + + @Test + public void threeArgInterrupted() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Action onDispose = mock(Action.class); + + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + Action action = mock(Action.class); + + Thread.currentThread().interrupt(); + + Maybe.never() + .doOnDispose(onDispose) + .blockingSubscribe(success, consumer, action); + + assertTrue("" + errors, errors.isEmpty()); + + verify(onDispose).run(); + verify(success, never()).accept(any()); + verify(action, never()).run(); + verify(consumer).accept(any(InterruptedException.class)); + }); + } + + @Test + public void observerSuccess() { + TestObserver to = new TestObserver<>(); + + Maybe.just(1) + .blockingSubscribe(to); + + to.assertResult(1); + } + + @Test + public void observerSuccessAsync() { + TestObserver to = new TestObserver<>(); + + Maybe.just(1) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation()) + .blockingSubscribe(to); + + to.assertResult(1); + } + + @Test + public void observerEmpty() { + TestObserver to = new TestObserver<>(); + + Maybe.empty() + .blockingSubscribe(to); + + to.assertResult(); + } + + @Test + public void observerEmptyAsync() { + TestObserver to = new TestObserver<>(); + + Maybe.empty() + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation()) + .blockingSubscribe(to); + + to.assertResult(); + } + + @Test + public void observerError() { + TestObserver to = new TestObserver<>(); + + Maybe.error(new TestException()) + .blockingSubscribe(to); + + to.assertFailure(TestException.class); + } + + @Test + public void observerErrorAsync() { + TestObserver to = new TestObserver<>(); + + Maybe.error(new TestException()) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation()) + .blockingSubscribe(to); + + to.assertFailure(TestException.class); + } + + @Test + public void observerDispose() throws Throwable { + Action onDispose = mock(Action.class); + + TestObserver to = new TestObserver<>(); + to.dispose(); + + Maybe.never() + .doOnDispose(onDispose) + .blockingSubscribe(to); + + to.assertEmpty(); + + verify(onDispose).run(); + } + + @Test + public void ovserverInterrupted() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Action onDispose = mock(Action.class); + + TestObserver to = new TestObserver<>(); + + Thread.currentThread().interrupt(); + + Maybe.never() + .doOnDispose(onDispose) + .blockingSubscribe(to); + + assertTrue("" + errors, errors.isEmpty()); + + verify(onDispose).run(); + to.assertFailure(InterruptedException.class); + }); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCacheTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCacheTest.java index a8d42ef6035..80f61f5931c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCacheTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCacheTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserverTest.java index e65b01e0702..1758a1116b0 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCallbackObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArrayEagerDelayErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArrayEagerDelayErrorTest.java new file mode 100644 index 00000000000..94e77bf55ad --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArrayEagerDelayErrorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Maybe; +import io.reactivex.rxjava3.exceptions.TestException; + +public class MaybeConcatArrayEagerDelayErrorTest { + + @Test + public void normal() { + Maybe.concatArrayEagerDelayError( + Maybe.just(1), + Maybe.error(new TestException()), + Maybe.empty(), + Maybe.just(2) + ) + .test() + .assertFailure(TestException.class, 1, 2); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArrayTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArrayTest.java index 301a8a35f5f..c2d6fcc0ae6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArrayTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatArrayTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,12 +18,13 @@ import java.io.IOException; import java.util.List; -import io.reactivex.rxjava3.disposables.Disposable; import org.junit.Test; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.subjects.MaybeSubject; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.TestHelper; @@ -188,4 +189,79 @@ public void subscribe(MaybeEmitter s) throws Exception { assertEquals(1, calls[0]); } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Maybe.concatArray(MaybeSubject.create(), MaybeSubject.create())); + } + + @Test + public void badRequestDelayError() { + TestHelper.assertBadRequestReported(Maybe.concatArrayDelayError(MaybeSubject.create(), MaybeSubject.create())); + } + + @Test + public void mixed() { + Maybe.concatArray( + Maybe.just(1), + Maybe.empty(), + Maybe.just(2), + Maybe.empty(), + Maybe.empty() + ) + .test() + .assertResult(1, 2); + } + + @Test + public void requestBeforeSuccess() { + MaybeSubject ms = MaybeSubject.create(); + TestSubscriber ts = Maybe.concatArray(ms, ms) + .test(); + + ts.assertEmpty(); + + ms.onSuccess(1); + + ts.assertResult(1, 1); + } + + @Test + public void requestBeforeComplete() { + MaybeSubject ms = MaybeSubject.create(); + TestSubscriber ts = Maybe.concatArray(ms, ms) + .test(); + + ts.assertEmpty(); + + ms.onComplete(); + + ts.assertResult(); + } + + @Test + public void requestBeforeSuccessDelayError() { + MaybeSubject ms = MaybeSubject.create(); + TestSubscriber ts = Maybe.concatArrayDelayError(ms, ms) + .test(); + + ts.assertEmpty(); + + ms.onSuccess(1); + + ts.assertResult(1, 1); + } + + @Test + public void requestBeforeCompleteDelayError() { + MaybeSubject ms = MaybeSubject.create(); + TestSubscriber ts = Maybe.concatArrayDelayError(ms, ms) + .test(); + + ts.assertEmpty(); + + ms.onComplete(); + + ts.assertResult(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatEagerTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatEagerTest.java new file mode 100644 index 00000000000..4c53fcddf3c --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatEagerTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import java.util.Arrays; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; + +public class MaybeConcatEagerTest { + + @Test + public void iterableNormal() { + Maybe.concatEager(Arrays.asList( + Maybe.just(1), + Maybe.empty(), + Maybe.just(2) + )) + .test() + .assertResult(1, 2); + } + + @Test + public void iterableNormalMaxConcurrency() { + Maybe.concatEager(Arrays.asList( + Maybe.just(1), + Maybe.empty(), + Maybe.just(2) + ), 1) + .test() + .assertResult(1, 2); + } + + @Test + public void iterableError() { + Maybe.concatEager(Arrays.asList( + Maybe.just(1), + Maybe.error(new TestException()), + Maybe.empty(), + Maybe.just(2) + )) + .test() + .assertFailure(TestException.class, 1); + } + + @Test + public void iterableErrorMaxConcurrency() { + Maybe.concatEager(Arrays.asList( + Maybe.just(1), + Maybe.error(new TestException()), + Maybe.empty(), + Maybe.just(2) + ), 1) + .test() + .assertFailure(TestException.class, 1); + } + + @Test + public void publisherNormal() { + Maybe.concatEager(Flowable.fromArray( + Maybe.just(1), + Maybe.empty(), + Maybe.just(2) + )) + .test() + .assertResult(1, 2); + } + + @Test + public void publisherNormalMaxConcurrency() { + Maybe.concatEager(Flowable.fromArray( + Maybe.just(1), + Maybe.empty(), + Maybe.just(2) + ), 1) + .test() + .assertResult(1, 2); + } + + @Test + public void publisherError() { + Maybe.concatEager(Flowable.fromArray( + Maybe.just(1), + Maybe.error(new TestException()), + Maybe.empty(), + Maybe.just(2) + )) + .test() + .assertFailure(TestException.class, 1); + } + + @Test + public void iterableDelayError() { + Maybe.concatEagerDelayError(Arrays.asList( + Maybe.just(1), + Maybe.error(new TestException()), + Maybe.empty(), + Maybe.just(2) + )) + .test() + .assertFailure(TestException.class, 1, 2); + } + + @Test + public void iterableDelayErrorMaxConcurrency() { + Maybe.concatEagerDelayError(Arrays.asList( + Maybe.just(1), + Maybe.error(new TestException()), + Maybe.empty(), + Maybe.just(2) + ), 1) + .test() + .assertFailure(TestException.class, 1, 2); + } + + @Test + public void publisherDelayError() { + Maybe.concatEagerDelayError(Flowable.fromArray( + Maybe.just(1), + Maybe.error(new TestException()), + Maybe.empty(), + Maybe.just(2) + )) + .test() + .assertFailure(TestException.class, 1, 2); + } + + @Test + public void publisherDelayErrorMaxConcurrency() { + Maybe.concatEagerDelayError(Flowable.fromArray( + Maybe.just(1), + Maybe.error(new TestException()), + Maybe.empty(), + Maybe.just(2) + ), 1) + .test() + .assertFailure(TestException.class, 1, 2); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatIterableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatIterableTest.java index 7450dc993bd..c8b90452636 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatIterableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatIterableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,6 +24,7 @@ import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.util.CrashingMappedIterable; import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.subjects.MaybeSubject; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.TestHelper; @@ -158,4 +159,12 @@ public void subscribe(MaybeEmitter s) throws Exception { assertEquals(1, calls[0]); } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(Maybe.concat(Arrays.asList( + MaybeSubject.create(), + MaybeSubject.create() + ))); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatMapCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatMapCompletableTest.java new file mode 100644 index 00000000000..dedd03a02ee --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatMapCompletableTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class MaybeConcatMapCompletableTest extends RxJavaTest { + + @Test + public void dispose() { + TestHelper.checkDisposed(Maybe.just(1).concatMapCompletable(new Function() { + @Override + public Completable apply(Integer v) throws Exception { + return Completable.complete(); + } + })); + } + + @Test + public void mapperThrows() { + Maybe.just(1) + .concatMapCompletable(new Function() { + @Override + public Completable apply(Integer v) throws Exception { + throw new TestException(); + } + }) + .test() + .assertFailure(TestException.class); + } + + @Test + public void mapperReturnsNull() { + Maybe.just(1) + .concatMapCompletable(new Function() { + @Override + public Completable apply(Integer v) throws Exception { + return null; + } + }) + .test() + .assertFailure(NullPointerException.class); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatMapSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatMapSingleTest.java new file mode 100644 index 00000000000..93695b52937 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatMapSingleTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class MaybeConcatMapSingleTest extends RxJavaTest { + @Test + public void flatMapSingleElementValue() { + Maybe.just(1).concatMapSingle(new Function>() { + @Override public SingleSource apply(final Integer integer) throws Exception { + if (integer == 1) { + return Single.just(2); + } + + return Single.just(1); + } + }) + .test() + .assertResult(2); + } + + @Test + public void flatMapSingleElementValueDifferentType() { + Maybe.just(1).concatMapSingle(new Function>() { + @Override public SingleSource apply(final Integer integer) throws Exception { + if (integer == 1) { + return Single.just("2"); + } + + return Single.just("1"); + } + }) + .test() + .assertResult("2"); + } + + @Test + public void flatMapSingleElementValueNull() { + Maybe.just(1).concatMapSingle(new Function>() { + @Override public SingleSource apply(final Integer integer) throws Exception { + return null; + } + }) + .to(TestHelper.testConsumer()) + .assertNoValues() + .assertError(NullPointerException.class) + .assertErrorMessage("The mapper returned a null SingleSource"); + } + + @Test + public void flatMapSingleElementValueErrorThrown() { + Maybe.just(1).concatMapSingle(new Function>() { + @Override public SingleSource apply(final Integer integer) throws Exception { + throw new RuntimeException("something went terribly wrong!"); + } + }) + .to(TestHelper.testConsumer()) + .assertNoValues() + .assertError(RuntimeException.class) + .assertErrorMessage("something went terribly wrong!"); + } + + @Test + public void flatMapSingleElementError() { + RuntimeException exception = new RuntimeException("test"); + + Maybe.error(exception).concatMapSingle(new Function>() { + @Override public SingleSource apply(final Object integer) throws Exception { + return Single.just(new Object()); + } + }) + .test() + .assertError(exception); + } + + @Test + public void flatMapSingleElementEmpty() { + Maybe.empty().concatMapSingle(new Function>() { + @Override public SingleSource apply(final Integer integer) throws Exception { + return Single.just(2); + } + }) + .test() + .assertNoValues() + .assertResult(); + } + + @Test + public void dispose() { + TestHelper.checkDisposed(Maybe.just(1).concatMapSingle(new Function>() { + @Override + public SingleSource apply(final Integer integer) throws Exception { + return Single.just(2); + } + })); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeMaybe(new Function, Maybe>() { + @Override + public Maybe apply(Maybe m) throws Exception { + return m.concatMapSingle(new Function>() { + @Override + public SingleSource apply(final Integer integer) throws Exception { + return Single.just(2); + } + }); + } + }); + } + + @Test + public void singleErrors() { + Maybe.just(1) + .concatMapSingle(new Function>() { + @Override + public SingleSource apply(final Integer integer) throws Exception { + return Single.error(new TestException()); + } + }) + .test() + .assertFailure(TestException.class); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatMapTest.java new file mode 100644 index 00000000000..04e5abfafd0 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatMapTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class MaybeConcatMapTest extends RxJavaTest { + + @Test + public void dispose() { + TestHelper.checkDisposed(Maybe.just(1).concatMap(new Function>() { + @Override + public MaybeSource apply(Integer v) throws Exception { + return Maybe.just(2); + } + })); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeMaybe(new Function, MaybeSource>() { + @Override + public MaybeSource apply(Maybe v) throws Exception { + return v.concatMap(new Function>() { + @Override + public MaybeSource apply(Integer v) throws Exception { + return Maybe.just(2); + } + }); + } + }); + } + + @Test + public void mainError() { + Maybe.error(new TestException()) + .concatMap(new Function>() { + @Override + public MaybeSource apply(Integer v) throws Exception { + return Maybe.just(2); + } + }) + .test() + .assertFailure(TestException.class); + } + + @Test + public void mainEmpty() { + Maybe.empty() + .concatMap(new Function>() { + @Override + public MaybeSource apply(Integer v) throws Exception { + return Maybe.just(2); + } + }) + .test() + .assertResult(); + } + + @Test + public void mapperThrows() { + Maybe.just(1) + .concatMap(new Function>() { + @Override + public MaybeSource apply(Integer v) throws Exception { + throw new TestException(); + } + }) + .test() + .assertFailure(TestException.class); + } + + @Test + public void mapperReturnsNull() { + Maybe.just(1) + .concatMap(new Function>() { + @Override + public MaybeSource apply(Integer v) throws Exception { + return null; + } + }) + .test() + .assertFailure(NullPointerException.class); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatPublisherTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatPublisherTest.java index 527de9734bf..ad334cac7b0 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatPublisherTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeConcatPublisherTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.maybe; import java.util.concurrent.Callable; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeContainsTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeContainsTest.java index 07a7abc77ba..ca019517d80 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeContainsTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeContainsTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCountTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCountTest.java index 669cb4e28c8..b223358ef27 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCountTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCountTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCreateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCreateTest.java index b0857c432fc..6bd42bce441 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCreateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeCreateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayOtherTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayOtherTest.java index 8ca50837ec6..f482834e297 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayOtherTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayOtherTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelaySubscriptionTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelaySubscriptionTest.java index bca4023f83d..dae5d6f68c7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelaySubscriptionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelaySubscriptionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -141,4 +141,9 @@ protected void subscribeActual(Subscriber subscriber) { RxJavaPlugins.reset(); } } + + @Test + public void doubleOnSubscribePublisher() { + TestHelper.checkDoubleOnSubscribeFlowableToMaybe(f -> Maybe.just(1).delaySubscription(f)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayTest.java index da75df361ce..4485f58f5ed 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDelayTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -53,16 +53,6 @@ public void complete() { .assertResult(); } - @Test(expected = NullPointerException.class) - public void nullUnit() { - Maybe.just(1).delay(1, null); - } - - @Test(expected = NullPointerException.class) - public void nullScheduler() { - Maybe.just(1).delay(1, TimeUnit.MILLISECONDS, null); - } - @Test public void disposeDuringDelay() { TestScheduler scheduler = new TestScheduler(); @@ -106,4 +96,32 @@ public Maybe apply(Maybe f) throws Exception { } }); } + + @Test + public void delayedErrorOnSuccess() { + final TestScheduler scheduler = new TestScheduler(); + final TestObserver observer = Maybe.just(1) + .delay(5, TimeUnit.SECONDS, scheduler, true) + .test(); + + scheduler.advanceTimeTo(2, TimeUnit.SECONDS); + observer.assertNoValues(); + + scheduler.advanceTimeTo(5, TimeUnit.SECONDS); + observer.assertValue(1); + } + + @Test + public void delayedErrorOnError() { + final TestScheduler scheduler = new TestScheduler(); + final TestObserver observer = Maybe.error(new TestException()) + .delay(5, TimeUnit.SECONDS, scheduler, true) + .test(); + + scheduler.advanceTimeTo(2, TimeUnit.SECONDS); + observer.assertNoErrors(); + + scheduler.advanceTimeTo(5, TimeUnit.SECONDS); + observer.assertError(TestException.class); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDematerializeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDematerializeTest.java new file mode 100644 index 00000000000..4f78295f76f --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDematerializeTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import static org.mockito.Mockito.*; +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.subjects.MaybeSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class MaybeDematerializeTest extends RxJavaTest { + + @Test + public void success() { + Maybe.just(Notification.createOnNext(1)) + .dematerialize(Functions.>identity()) + .test() + .assertResult(1); + } + + @Test + public void empty() { + Maybe.just(Notification.createOnComplete()) + .dematerialize(Functions.>identity()) + .test() + .assertResult(); + } + + @Test + public void emptySource() throws Throwable { + @SuppressWarnings("unchecked") + Function, Notification> function = mock(Function.class); + + Maybe.>empty() + .dematerialize(function) + .test() + .assertResult(); + + verify(function, never()).apply(any()); + } + + @Test + public void error() { + Maybe.>error(new TestException()) + .dematerialize(Functions.>identity()) + .test() + .assertFailure(TestException.class); + } + + @Test + public void errorNotification() { + Maybe.just(Notification.createOnError(new TestException())) + .dematerialize(Functions.>identity()) + .test() + .assertFailure(TestException.class); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeMaybe(new Function, MaybeSource>() { + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public MaybeSource apply(Maybe v) throws Exception { + return v.dematerialize((Function)Functions.identity()); + } + }); + } + + @Test + public void dispose() { + TestHelper.checkDisposed(MaybeSubject.>create().dematerialize(Functions.>identity())); + } + + @Test + public void selectorCrash() { + Maybe.just(Notification.createOnNext(1)) + .dematerialize(new Function, Notification>() { + @Override + public Notification apply(Notification v) throws Exception { + throw new TestException(); + } + }) + .test() + .assertFailure(TestException.class); + } + + @Test + public void selectorNull() { + Maybe.just(Notification.createOnNext(1)) + .dematerialize(Functions.justFunction((Notification)null)) + .test() + .assertFailure(NullPointerException.class); + } + + @Test + public void selectorDifferentType() { + Maybe.just(Notification.createOnNext(1)) + .dematerialize(new Function, Notification>() { + @Override + public Notification apply(Notification v) throws Exception { + return Notification.createOnNext("Value-" + 1); + } + }) + .test() + .assertResult("Value-1"); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDetachTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDetachTest.java index 2c96cbfe884..6498e98371e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDetachTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDetachTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoAfterSuccessTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoAfterSuccessTest.java index d772193241d..a961f0b11c2 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoAfterSuccessTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoAfterSuccessTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -77,11 +77,6 @@ public void empty() { assertTrue(values.isEmpty()); } - @Test(expected = NullPointerException.class) - public void consumerNull() { - Maybe.just(1).doAfterSuccess(null); - } - @Test public void justConditional() { Maybe.just(1) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoFinallyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoFinallyTest.java index 1be982960e6..f98c3cf810a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoFinallyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoFinallyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -115,11 +115,6 @@ public void normalErrorConditional() { assertEquals(1, calls); } - @Test(expected = NullPointerException.class) - public void nullAction() { - Maybe.just(1).doFinally(null); - } - @Test public void actionThrows() { List errors = TestHelper.trackPluginErrors(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnEventTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnEventTest.java index abe91714e78..37614ec7938 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnEventTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnEventTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnLifecycleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnLifecycleTest.java new file mode 100644 index 00000000000..39d71105ca5 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnLifecycleTest.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.subjects.MaybeSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class MaybeDoOnLifecycleTest extends RxJavaTest { + + @Test + public void success() throws Throwable { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + Maybe.just(1) + .doOnLifecycle(onSubscribe, onDispose) + .test() + .assertResult(1); + + verify(onSubscribe).accept(any()); + verify(onDispose, never()).run(); + } + + @Test + public void empty() throws Throwable { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + Maybe.empty() + .doOnLifecycle(onSubscribe, onDispose) + .test() + .assertResult(); + + verify(onSubscribe).accept(any()); + verify(onDispose, never()).run(); + } + + @Test + public void error() throws Throwable { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + Maybe.error(new TestException()) + .doOnLifecycle(onSubscribe, onDispose) + .test() + .assertFailure(TestException.class); + + verify(onSubscribe).accept(any()); + verify(onDispose, never()).run(); + } + + @Test + public void onSubscribeCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + doThrow(new TestException("First")).when(onSubscribe).accept(any()); + + Disposable bs = Disposable.empty(); + + new Maybe() { + @Override + protected void subscribeActual(MaybeObserver observer) { + observer.onSubscribe(bs); + observer.onError(new TestException("Second")); + observer.onComplete(); + observer.onSuccess(1); + } + } + .doOnLifecycle(onSubscribe, onDispose) + .to(TestHelper.testConsumer()) + .assertFailureAndMessage(TestException.class, "First"); + + assertTrue(bs.isDisposed()); + + TestHelper.assertUndeliverable(errors, 0, TestException.class, "Second"); + + verify(onSubscribe).accept(any()); + verify(onDispose, never()).run(); + }); + } + + @Test + public void onDisposeCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + doThrow(new TestException("First")).when(onDispose).run(); + + MaybeSubject ms = MaybeSubject.create(); + + TestObserver to = ms + .doOnLifecycle(onSubscribe, onDispose) + .test(); + + assertTrue(ms.hasObservers()); + + to.dispose(); + + assertFalse(ms.hasObservers()); + + TestHelper.assertUndeliverable(errors, 0, TestException.class, "First"); + + verify(onSubscribe).accept(any()); + verify(onDispose).run(); + }); + } + + @Test + public void dispose() throws Throwable { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + MaybeSubject ms = MaybeSubject.create(); + + TestObserver to = ms + .doOnLifecycle(onSubscribe, onDispose) + .test(); + + assertTrue(ms.hasObservers()); + + to.dispose(); + + assertFalse(ms.hasObservers()); + + verify(onSubscribe).accept(any()); + verify(onDispose).run(); + } + + @Test + public void isDisposed() { + TestHelper.checkDisposed(MaybeSubject.create().doOnLifecycle(d -> { }, () -> { })); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeMaybe(m -> m.doOnLifecycle(d -> { }, () -> { })); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnTerminateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnTerminateTest.java index 8f931852075..4471db0ee1d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnTerminateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeDoOnTerminateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,11 +27,6 @@ public class MaybeDoOnTerminateTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void doOnTerminate() { - Maybe.just(1).doOnTerminate(null); - } - @Test public void doOnTerminateSuccess() { final AtomicBoolean atomicBoolean = new AtomicBoolean(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEmptyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEmptyTest.java index c477416241e..a2197189364 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEmptyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEmptyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,7 +18,7 @@ import org.junit.Test; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.internal.fuseable.ScalarSupplier; +import io.reactivex.rxjava3.operators.ScalarSupplier; public class MaybeEmptyTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEqualTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEqualTest.java index 8a42f12d5b1..e7b6ea4302a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEqualTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeEqualTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeErrorTest.java index b75eea1906b..f67dc7884b9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeErrorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeErrorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFilterSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFilterSingleTest.java index 2647f760ce3..52682cc208c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFilterSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFilterSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapBiSelectorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapBiSelectorTest.java index f0db482a621..67227bb4227 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapBiSelectorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapBiSelectorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapCompletableTest.java index a76af597b28..053f1e3e401 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableFlowableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableFlowableTest.java index 1c840a22951..e4bcaa9f77d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableFlowableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableFlowableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,10 +24,11 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.util.CrashingIterable; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.schedulers.Schedulers; -import io.reactivex.rxjava3.subjects.PublishSubject; +import io.reactivex.rxjava3.subjects.*; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; @@ -120,6 +121,20 @@ public Iterable apply(Integer v) throws Exception { .assertResult(1); } + @Test + public void take2() { + Maybe.just(1).flattenAsFlowable(new Function>() { + @Override + public Iterable apply(Integer v) throws Exception { + return Arrays.asList(v, v + 1); + } + }) + .doOnSubscribe(s -> s.request(Long.MAX_VALUE)) + .take(1) + .test() + .assertResult(1); + } + @Test public void fused() { TestSubscriberEx ts = new TestSubscriberEx().setInitialFusionMode(QueueFuseable.ANY); @@ -562,4 +577,33 @@ public void remove() { ts.request(Long.MAX_VALUE); ts.assertValues(1, 1).assertNoErrors().assertNotComplete(); } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(MaybeSubject.create().flattenAsFlowable(v -> Arrays.asList(v))); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeMaybeToFlowable(m -> m.flattenAsFlowable(v -> Arrays.asList(v))); + } + + @Test + public void onSuccessRequestRace() { + List list = Arrays.asList(1); + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + + MaybeSubject ms = MaybeSubject.create(); + + TestSubscriber ts = ms.flattenAsFlowable(v -> list) + .test(0L); + + TestHelper.race( + () -> ms.onSuccess(1), + () -> ts.request(1) + ); + + ts.assertResult(1); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableObservableTest.java index 601da820a79..d06f6261195 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapIterableObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -25,8 +25,9 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.util.CrashingIterable; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapNotificationTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapNotificationTest.java index 6faec2ab9a5..1d4d4f0d5ef 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapNotificationTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapNotificationTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingleElementTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingleElementTest.java index c3409aed66d..2f5cf424260 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingleElementTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingleElementTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,15 +21,9 @@ import io.reactivex.rxjava3.testsupport.TestHelper; public class MaybeFlatMapSingleElementTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void flatMapSingleElementNull() { - Maybe.just(1) - .flatMapSingleElement(null); - } - @Test - public void flatMapSingleElementValue() { - Maybe.just(1).flatMapSingleElement(new Function>() { + public void flatMapSingleValue() { + Maybe.just(1).flatMapSingle(new Function>() { @Override public SingleSource apply(final Integer integer) throws Exception { if (integer == 1) { return Single.just(2); @@ -43,8 +37,8 @@ public void flatMapSingleElementValue() { } @Test - public void flatMapSingleElementValueDifferentType() { - Maybe.just(1).flatMapSingleElement(new Function>() { + public void flatMapSingleValueDifferentType() { + Maybe.just(1).flatMapSingle(new Function>() { @Override public SingleSource apply(final Integer integer) throws Exception { if (integer == 1) { return Single.just("2"); @@ -58,8 +52,8 @@ public void flatMapSingleElementValueDifferentType() { } @Test - public void flatMapSingleElementValueNull() { - Maybe.just(1).flatMapSingleElement(new Function>() { + public void flatMapSingleValueNull() { + Maybe.just(1).flatMapSingle(new Function>() { @Override public SingleSource apply(final Integer integer) throws Exception { return null; } @@ -71,8 +65,8 @@ public void flatMapSingleElementValueNull() { } @Test - public void flatMapSingleElementValueErrorThrown() { - Maybe.just(1).flatMapSingleElement(new Function>() { + public void flatMapSingleValueErrorThrown() { + Maybe.just(1).flatMapSingle(new Function>() { @Override public SingleSource apply(final Integer integer) throws Exception { throw new RuntimeException("something went terribly wrong!"); } @@ -84,10 +78,10 @@ public void flatMapSingleElementValueErrorThrown() { } @Test - public void flatMapSingleElementError() { + public void flatMapSingleError() { RuntimeException exception = new RuntimeException("test"); - Maybe.error(exception).flatMapSingleElement(new Function>() { + Maybe.error(exception).flatMapSingle(new Function>() { @Override public SingleSource apply(final Object integer) throws Exception { return Single.just(new Object()); } @@ -97,8 +91,8 @@ public void flatMapSingleElementError() { } @Test - public void flatMapSingleElementEmpty() { - Maybe.empty().flatMapSingleElement(new Function>() { + public void flatMapSingleEmpty() { + Maybe.empty().flatMapSingle(new Function>() { @Override public SingleSource apply(final Integer integer) throws Exception { return Single.just(2); } @@ -110,7 +104,7 @@ public void flatMapSingleElementEmpty() { @Test public void dispose() { - TestHelper.checkDisposed(Maybe.just(1).flatMapSingleElement(new Function>() { + TestHelper.checkDisposed(Maybe.just(1).flatMapSingle(new Function>() { @Override public SingleSource apply(final Integer integer) throws Exception { return Single.just(2); @@ -123,7 +117,7 @@ public void doubleOnSubscribe() { TestHelper.checkDoubleOnSubscribeMaybe(new Function, Maybe>() { @Override public Maybe apply(Maybe m) throws Exception { - return m.flatMapSingleElement(new Function>() { + return m.flatMapSingle(new Function>() { @Override public SingleSource apply(final Integer integer) throws Exception { return Single.just(2); @@ -136,7 +130,7 @@ public SingleSource apply(final Integer integer) throws Exception { @Test public void singleErrors() { Maybe.just(1) - .flatMapSingleElement(new Function>() { + .flatMapSingle(new Function>() { @Override public SingleSource apply(final Integer integer) throws Exception { return Single.error(new TestException()); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingleTest.java index 60b1a98f3b8..cdf7f36f1f2 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlatMapSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,12 +23,6 @@ import io.reactivex.rxjava3.testsupport.TestHelper; public class MaybeFlatMapSingleTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void flatMapSingleNull() { - Maybe.just(1) - .flatMapSingle(null); - } - @Test public void flatMapSingleValue() { Maybe.just(1).flatMapSingle(new Function>() { @@ -40,6 +34,7 @@ public void flatMapSingleValue() { return Single.just(1); } }) + .toSingle() .test() .assertResult(2); } @@ -55,6 +50,7 @@ public void flatMapSingleValueDifferentType() { return Single.just("1"); } }) + .toSingle() .test() .assertResult("2"); } @@ -66,6 +62,7 @@ public void flatMapSingleValueNull() { return null; } }) + .toSingle() .to(TestHelper.testConsumer()) .assertNoValues() .assertError(NullPointerException.class) @@ -79,6 +76,7 @@ public void flatMapSingleValueErrorThrown() { throw new RuntimeException("something went terribly wrong!"); } }) + .toSingle() .to(TestHelper.testConsumer()) .assertNoValues() .assertError(RuntimeException.class) @@ -94,6 +92,7 @@ public void flatMapSingleError() { return Single.just(new Object()); } }) + .toSingle() .test() .assertError(exception); } @@ -105,6 +104,7 @@ public void flatMapSingleEmpty() { return Single.just(2); } }) + .toSingle() .test() .assertNoValues() .assertError(NoSuchElementException.class); @@ -117,7 +117,7 @@ public void dispose() { public SingleSource apply(final Integer integer) throws Exception { return Single.just(2); } - })); + }).toSingle()); } @Test @@ -130,7 +130,7 @@ public SingleSource apply(Maybe m) throws Exception { public SingleSource apply(final Integer integer) throws Exception { return Single.just(2); } - }); + }).toSingle(); } }); } @@ -144,6 +144,7 @@ public SingleSource apply(final Integer integer) throws Exception { return Single.error(new TestException()); } }) + .toSingle() .test() .assertFailure(TestException.class); } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlattenTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlattenTest.java index bcdaa3f061a..30c0cfdeb80 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlattenTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFlattenTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromActionTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromActionTest.java index ccd87877cd9..32f37c1cd78 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromActionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromActionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,11 +30,6 @@ import io.reactivex.rxjava3.testsupport.TestHelper; public class MaybeFromActionTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromActionNull() { - Maybe.fromAction(null); - } - @Test public void fromAction() { final AtomicInteger atomicInteger = new AtomicInteger(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCallableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCallableTest.java index b934f98fdfe..dec0d8e33e8 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCallableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCallableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -34,11 +34,6 @@ import io.reactivex.rxjava3.testsupport.TestHelper; public class MaybeFromCallableTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromCallableNull() { - Maybe.fromCallable(null); - } - @Test public void fromCallable() { final AtomicInteger atomicInteger = new AtomicInteger(); @@ -218,4 +213,18 @@ public String answer(InvocationOnMock invocation) throws Throwable { verify(observer).onSubscribe(any(Disposable.class)); verifyNoMoreInteractions(observer); } + + @Test + public void disposeUpfront() { + Maybe.fromCallable(() -> 1) + .test(true) + .assertEmpty(); + } + + @Test + public void success() { + Maybe.fromCallable(() -> 1) + .test() + .assertResult(1); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCompletableTest.java index 3549901863e..40f00e371ab 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,11 +24,6 @@ import io.reactivex.rxjava3.testsupport.TestHelper; public class MaybeFromCompletableTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromCompletableNull() { - Maybe.fromCompletable(null); - } - @Test public void fromCompletable() { Maybe.fromCompletable(Completable.complete()) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromFutureTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromFutureTest.java index 98ea62255e0..fb88c60a721 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromFutureTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromFutureTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromObservableTest.java new file mode 100644 index 00000000000..311f33e4d42 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromObservableTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; + +public class MaybeFromObservableTest extends RxJavaTest { + + @Test + public void empty() { + Maybe.fromObservable(Observable.empty().hide()) + .test() + .assertResult(); + } + + @Test + public void just() { + Maybe.fromObservable(Observable.just(1).hide()) + .test() + .assertResult(1); + } + + @Test + public void range() { + Maybe.fromObservable(Observable.range(1, 5).hide()) + .test() + .assertResult(1); + } + + @Test + public void error() { + Maybe.fromObservable(Observable.error(new TestException()).hide()) + .test() + .assertFailure(TestException.class); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromPubisherTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromPubisherTest.java new file mode 100644 index 00000000000..c51c23bae41 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromPubisherTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; + +public class MaybeFromPubisherTest extends RxJavaTest { + + @Test + public void empty() { + Maybe.fromPublisher(Flowable.empty().hide()) + .test() + .assertResult(); + } + + @Test + public void just() { + Maybe.fromPublisher(Flowable.just(1).hide()) + .test() + .assertResult(1); + } + + @Test + public void range() { + Maybe.fromPublisher(Flowable.range(1, 5).hide()) + .test() + .assertResult(1); + } + + @Test + public void error() { + Maybe.fromPublisher(Flowable.error(new TestException()).hide()) + .test() + .assertFailure(TestException.class); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromRunnableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromRunnableTest.java index b5bc8d9727b..5d1db4ad4d3 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromRunnableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromRunnableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,11 +30,6 @@ import io.reactivex.rxjava3.testsupport.TestHelper; public class MaybeFromRunnableTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromRunnableNull() { - Maybe.fromRunnable(null); - } - @Test public void fromRunnable() { final AtomicInteger atomicInteger = new AtomicInteger(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSingleTest.java index 989bb789859..27c13626f6e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,11 +24,6 @@ import io.reactivex.rxjava3.testsupport.TestHelper; public class MaybeFromSingleTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromSingleNull() { - Maybe.fromSingle(null); - } - @Test public void fromSingle() { Maybe.fromSingle(Single.just(1)) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSupplierTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSupplierTest.java index b8196e39174..bcbe0783ccf 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSupplierTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeFromSupplierTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -35,11 +35,6 @@ public class MaybeFromSupplierTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void fromSupplierNull() { - Maybe.fromSupplier(null); - } - @Test public void fromSupplier() { final AtomicInteger atomicInteger = new AtomicInteger(); @@ -219,4 +214,23 @@ public String answer(InvocationOnMock invocation) throws Throwable { verify(observer).onSubscribe(any(Disposable.class)); verifyNoMoreInteractions(observer); } + + @Test + public void success() { + Maybe.fromSupplier(() -> 1) + .test() + .assertResult(1); + } + + @Test + public void disposeUpfront() throws Throwable { + @SuppressWarnings("unchecked") + Supplier supplier = mock(Supplier.class); + + Maybe.fromSupplier(supplier) + .test(true) + .assertEmpty(); + + verify(supplier, never()).get(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeHideTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeHideTest.java index 4428b576999..11a1cbb1458 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeHideTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeHideTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,7 +20,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.ScalarSupplier; +import io.reactivex.rxjava3.operators.ScalarSupplier; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.testsupport.TestHelper; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIgnoreElementTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIgnoreElementTest.java index c41def19d3c..a7ab2f20240 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIgnoreElementTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIgnoreElementTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmptySingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmptySingleTest.java index 5a6021a48bf..23ead596390 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmptySingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmptySingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmptyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmptyTest.java index a7c208d2b58..a3a4a893c9f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmptyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeIsEmptyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeJustTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeJustTest.java index 6e61427a155..a49ac11a41a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeJustTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeJustTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,7 +18,7 @@ import org.junit.Test; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.internal.fuseable.ScalarSupplier; +import io.reactivex.rxjava3.operators.ScalarSupplier; public class MaybeJustTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMapTest.java index 52598869767..b58b78b26f5 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMaterializeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMaterializeTest.java index 57a478d112e..0c7f5704348 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMaterializeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMaterializeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeArrayTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeArrayTest.java index 6b886fd8947..bf4f7313dc8 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeArrayTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeArrayTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,16 +17,17 @@ import java.util.*; -import io.reactivex.rxjava3.disposables.Disposable; import org.junit.Test; import org.reactivestreams.Subscription; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.operators.maybe.MaybeMergeArray.MergeMaybeObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.subjects.PublishSubject; +import io.reactivex.rxjava3.subjects.*; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; @@ -250,4 +251,25 @@ public void onComplete() { } }); } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported( + Maybe.mergeArray(MaybeSubject.create(), MaybeSubject.create()) + ); + } + + @Test + public void cancel2() { + TestHelper.checkDisposed(Maybe.mergeArray(MaybeSubject.create(), MaybeSubject.create())); + } + + @Test + public void take() { + Maybe.mergeArray(Maybe.just(1), Maybe.empty(), Maybe.just(2)) + .doOnSubscribe(s -> s.request(Long.MAX_VALUE)) + .take(1) + .test() + .assertResult(1); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeTest.java index 8ce37cb7bec..0bf38ccc0fe 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeWithTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeWithTest.java index ab4a0b89553..dd4d0817a8c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeWithTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeMergeWithTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOfTypeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOfTypeTest.java index 0e459ffffbd..5d58b9ff906 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOfTypeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOfTypeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorXTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorXTest.java index f3a9b9345cd..2cbc2fe427b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorXTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeOnErrorXTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -98,22 +98,6 @@ public void onErrorResumeNext() { .assertResult(1); } - @Test - public void onExceptionResumeNext() { - Maybe.error(new TestException()) - .onExceptionResumeNext(Maybe.just(1)) - .test() - .assertResult(1); - } - - @Test - public void onExceptionResumeNextPassthrough() { - Maybe.error(new AssertionError()) - .onExceptionResumeNext(Maybe.just(1)) - .test() - .assertFailure(AssertionError.class); - } - @Test public void onErrorResumeNextFunctionThrows() { TestHelper.assertCompositeExceptions(Maybe.error(new TestException()) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybePeekTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybePeekTest.java index cbf4d60b34b..ade9039ecaa 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybePeekTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybePeekTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSafeSubscribeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSafeSubscribeTest.java new file mode 100644 index 00000000000..85919751d4c --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSafeSubscribeTest.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import java.io.IOException; + +import org.junit.Test; +import org.mockito.InOrder; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class MaybeSafeSubscribeTest { + + @Test + public void normalSuccess() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + MaybeObserver consumer = mock(MaybeObserver.class); + + Maybe.just(1) + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onSuccess(1); + order.verifyNoMoreInteractions(); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void normalError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + MaybeObserver consumer = mock(MaybeObserver.class); + + Maybe.error(new TestException()) + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onError(any(TestException.class)); + order.verifyNoMoreInteractions(); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void normalEmpty() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + MaybeObserver consumer = mock(MaybeObserver.class); + + Maybe.empty() + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onComplete(); + order.verifyNoMoreInteractions(); + }); + } + + @Test + public void onSubscribeCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + MaybeObserver consumer = mock(MaybeObserver.class); + doThrow(new TestException()).when(consumer).onSubscribe(any()); + + Disposable d = Disposable.empty(); + + new Maybe() { + @Override + protected void subscribeActual(@NonNull MaybeObserver observer) { + observer.onSubscribe(d); + // none of the following should arrive at the consumer + observer.onSuccess(1); + observer.onError(new IOException()); + observer.onComplete(); + } + } + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verifyNoMoreInteractions(); + + assertTrue(d.isDisposed()); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + TestHelper.assertUndeliverable(errors, 1, IOException.class); + }); + } + + @Test + public void onSuccessCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + MaybeObserver consumer = mock(MaybeObserver.class); + doThrow(new TestException()).when(consumer).onSuccess(any()); + + new Maybe() { + @Override + protected void subscribeActual(@NonNull MaybeObserver observer) { + observer.onSubscribe(Disposable.empty()); + observer.onSuccess(1); + } + } + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onSuccess(1); + order.verifyNoMoreInteractions(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void onErrorCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + MaybeObserver consumer = mock(MaybeObserver.class); + doThrow(new TestException()).when(consumer).onError(any()); + + new Maybe() { + @Override + protected void subscribeActual(@NonNull MaybeObserver observer) { + observer.onSubscribe(Disposable.empty()); + // none of the following should arrive at the consumer + observer.onError(new IOException()); + } + } + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onError(any(IOException.class)); + order.verifyNoMoreInteractions(); + + TestHelper.assertError(errors, 0, CompositeException.class); + + CompositeException compositeException = (CompositeException)errors.get(0); + TestHelper.assertError(compositeException.getExceptions(), 0, IOException.class); + TestHelper.assertError(compositeException.getExceptions(), 1, TestException.class); + }); + } + + @Test + public void onCompleteCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + MaybeObserver consumer = mock(MaybeObserver.class); + doThrow(new TestException()).when(consumer).onComplete(); + + new Maybe() { + @Override + protected void subscribeActual(@NonNull MaybeObserver observer) { + observer.onSubscribe(Disposable.empty()); + // none of the following should arrive at the consumer + observer.onComplete(); + } + } + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onComplete(); + order.verifyNoMoreInteractions(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeStartWithTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeStartWithTest.java new file mode 100644 index 00000000000..31b03141580 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeStartWithTest.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import static org.mockito.Mockito.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; + +public class MaybeStartWithTest { + + @Test + public void justCompletableComplete() { + Maybe.just(1).startWith(Completable.complete()) + .test() + .assertResult(1); + } + + @Test + public void emptyCompletableComplete() { + Maybe.empty().startWith(Completable.complete()) + .test() + .assertResult(); + } + + @Test + public void runCompletableError() { + Runnable run = mock(Runnable.class); + + Maybe.fromRunnable(run).startWith(Completable.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } + + @Test + public void justSingleJust() { + Maybe.just(1).startWith(Single.just(2)) + .test() + .assertResult(2, 1); + } + + @Test + public void emptySingleJust() { + Runnable run = mock(Runnable.class); + + Maybe.fromRunnable(run) + .startWith(Single.just(2)) + .test() + .assertResult(2); + + verify(run).run(); + } + + @Test + public void runSingleError() { + Runnable run = mock(Runnable.class); + + Maybe.fromRunnable(run).startWith(Single.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } + + @Test + public void justMaybeJust() { + Maybe.just(1).startWith(Maybe.just(2)) + .test() + .assertResult(2, 1); + } + + @Test + public void emptyMaybeJust() { + Runnable run = mock(Runnable.class); + + Maybe.fromRunnable(run) + .startWith(Maybe.just(2)) + .test() + .assertResult(2); + + verify(run).run(); + } + + @Test + public void runMaybeError() { + Runnable run = mock(Runnable.class); + + Maybe.fromRunnable(run).startWith(Maybe.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } + + @Test + public void justObservableJust() { + Maybe.just(1).startWith(Observable.just(2, 3, 4, 5)) + .test() + .assertResult(2, 3, 4, 5, 1); + } + + @Test + public void emptyObservableJust() { + Runnable run = mock(Runnable.class); + + Maybe.fromRunnable(run) + .startWith(Observable.just(2, 3, 4, 5)) + .test() + .assertResult(2, 3, 4, 5); + + verify(run).run(); + } + + @Test + public void emptyObservableEmpty() { + Runnable run = mock(Runnable.class); + Runnable run2 = mock(Runnable.class); + + Maybe.fromRunnable(run) + .startWith(Observable.fromRunnable(run2)) + .test() + .assertResult(); + + verify(run).run(); + verify(run2).run(); + } + + @Test + public void runObservableError() { + Runnable run = mock(Runnable.class); + + Maybe.fromRunnable(run).startWith(Observable.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } + + @Test + public void justFlowableJust() { + Maybe.just(1).startWith(Flowable.just(2, 3, 4, 5)) + .test() + .assertResult(2, 3, 4, 5, 1); + } + + @Test + public void emptyFlowableJust() { + Runnable run = mock(Runnable.class); + + Maybe.fromRunnable(run) + .startWith(Flowable.just(2, 3, 4, 5)) + .test() + .assertResult(2, 3, 4, 5); + + verify(run).run(); + } + + @Test + public void emptyFlowableEmpty() { + Runnable run = mock(Runnable.class); + Runnable run2 = mock(Runnable.class); + + Maybe.fromRunnable(run) + .startWith(Flowable.fromRunnable(run2)) + .test() + .assertResult(); + + verify(run).run(); + verify(run2).run(); + } + + @Test + public void runFlowableError() { + Runnable run = mock(Runnable.class); + + Maybe.fromRunnable(run).startWith(Flowable.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSubscribeOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSubscribeOnTest.java index 1043a848b8b..3f5a29bc239 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSubscribeOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSubscribeOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmptySingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmptySingleTest.java index ceed4345d30..153b183287e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmptySingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmptySingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmptyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmptyTest.java index 423d6ad1ac8..f15f5ae8be7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmptyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchIfEmptyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchOnNextTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchOnNextTest.java new file mode 100644 index 00000000000..7a502faa28c --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeSwitchOnNextTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.subjects.MaybeSubject; +import io.reactivex.rxjava3.subscribers.TestSubscriber; + +public class MaybeSwitchOnNextTest extends RxJavaTest { + + @Test + public void normal() { + Maybe.switchOnNext( + Flowable.range(1, 10) + .map(v -> { + if (v % 2 == 0) { + return Maybe.just(v); + } + return Maybe.empty(); + }) + ) + .test() + .assertResult(2, 4, 6, 8, 10); + } + + @Test + public void normalDelayError() { + Maybe.switchOnNextDelayError( + Flowable.range(1, 10) + .map(v -> { + if (v % 2 == 0) { + return Maybe.just(v); + } + return Maybe.empty(); + }) + ) + .test() + .assertResult(2, 4, 6, 8, 10); + } + + @Test + public void noDelaySwitch() { + PublishProcessor> pp = PublishProcessor.create(); + + TestSubscriber ts = Maybe.switchOnNext(pp).test(); + + assertTrue(pp.hasSubscribers()); + + ts.assertEmpty(); + + MaybeSubject ms1 = MaybeSubject.create(); + MaybeSubject ms2 = MaybeSubject.create(); + + pp.onNext(ms1); + + assertTrue(ms1.hasObservers()); + + pp.onNext(ms2); + + assertFalse(ms1.hasObservers()); + assertTrue(ms2.hasObservers()); + + pp.onComplete(); + + assertTrue(ms2.hasObservers()); + + ms2.onSuccess(1); + + ts.assertResult(1); + } + + @Test + public void delaySwitch() { + PublishProcessor> pp = PublishProcessor.create(); + + TestSubscriber ts = Maybe.switchOnNextDelayError(pp).test(); + + assertTrue(pp.hasSubscribers()); + + ts.assertEmpty(); + + MaybeSubject ms1 = MaybeSubject.create(); + MaybeSubject ms2 = MaybeSubject.create(); + + pp.onNext(ms1); + + assertTrue(ms1.hasObservers()); + + pp.onNext(ms2); + + assertFalse(ms1.hasObservers()); + assertTrue(ms2.hasObservers()); + + assertTrue(ms2.hasObservers()); + + ms2.onError(new TestException()); + + assertTrue(pp.hasSubscribers()); + + ts.assertEmpty(); + + pp.onComplete(); + + ts.assertFailure(TestException.class); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilPublisherTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilPublisherTest.java index e615c733e87..f5ce2495148 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilPublisherTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilPublisherTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilTest.java index 5c7d8f956d5..20ce1cfa417 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTakeUntilTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeIntervalTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeIntervalTest.java new file mode 100644 index 00000000000..bd50202ae45 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeIntervalTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Maybe; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.schedulers.*; +import io.reactivex.rxjava3.subjects.MaybeSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class MaybeTimeIntervalTest { + + @Test + public void just() { + Maybe.just(1) + .timeInterval() + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void empty() { + Maybe.empty() + .timeInterval() + .test() + .assertResult(); + } + + @Test + public void error() { + Maybe.error(new TestException()) + .timeInterval() + .test() + .assertFailure(TestException.class); + } + + @Test + public void justSeconds() { + Maybe.just(1) + .timeInterval(TimeUnit.SECONDS) + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void justScheduler() { + Maybe.just(1) + .timeInterval(Schedulers.single()) + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void justSecondsScheduler() { + Maybe.just(1) + .timeInterval(TimeUnit.SECONDS, Schedulers.single()) + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeMaybe(m -> m.timeInterval()); + } + + @Test + public void dispose() { + TestHelper.checkDisposed(MaybeSubject.create().timeInterval()); + } + + @Test + public void timeInfo() { + TestScheduler scheduler = new TestScheduler(); + + MaybeSubject ms = MaybeSubject.create(); + + TestObserver> to = ms + .timeInterval(scheduler) + .test(); + + scheduler.advanceTimeBy(1000, TimeUnit.MILLISECONDS); + + ms.onSuccess(1); + + to.assertResult(new Timed<>(1, 1000L, TimeUnit.MILLISECONDS)); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutPublisherTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutPublisherTest.java index 188db935976..efa2ce6ff69 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutPublisherTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutPublisherTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,7 +19,9 @@ import org.junit.Test; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.observers.TestObserver; @@ -231,4 +233,29 @@ public Object apply(Flowable f) throws Exception { } }, false, null, 1, 1); } + + @Test + public void mainSuccessAfterOtherSignal() { + PublishProcessor pp = PublishProcessor.create(); + + new Maybe() { + @Override + protected void subscribeActual(@NonNull MaybeObserver observer) { + observer.onSubscribe(Disposable.empty()); + pp.onNext(2); + observer.onSuccess(1); + } + } + .timeout(pp) + .test() + .assertFailure(TimeoutException.class); + } + + @Test + public void mainSuccess() { + Maybe.just(1) + .timeout(Flowable.never()) + .test() + .assertResult(1); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutTest.java index 7e30ce6a49d..b5b61a6ffca 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimeoutTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,12 +19,15 @@ import org.junit.Test; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.subjects.MaybeSubject; import io.reactivex.rxjava3.testsupport.*; public class MaybeTimeoutTest extends RxJavaTest { @@ -341,4 +344,21 @@ public void run() { } } } + + @Test + public void mainSuccessAfterOtherSignal() { + MaybeSubject ms = MaybeSubject.create(); + + new Maybe() { + @Override + protected void subscribeActual(@NonNull MaybeObserver observer) { + observer.onSubscribe(Disposable.empty()); + ms.onSuccess(2); + observer.onSuccess(1); + } + } + .timeout(ms) + .test() + .assertFailure(TimeoutException.class); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimerTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimerTest.java index 06a54ad90c2..05ffdf0562b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimerTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -37,7 +37,7 @@ public void dispose() { public void timerInterruptible() throws Exception { ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); try { - for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec) }) { + for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec, true) }) { final AtomicBoolean interrupted = new AtomicBoolean(); TestObserver to = Maybe.timer(1, TimeUnit.MILLISECONDS, s) .map(new Function() { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimestampTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimestampTest.java new file mode 100644 index 00000000000..935147a9060 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeTimestampTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Maybe; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.schedulers.*; +import io.reactivex.rxjava3.subjects.MaybeSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class MaybeTimestampTest { + + @Test + public void just() { + Maybe.just(1) + .timestamp() + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void empty() { + Maybe.empty() + .timestamp() + .test() + .assertResult(); + } + + @Test + public void error() { + Maybe.error(new TestException()) + .timestamp() + .test() + .assertFailure(TestException.class); + } + + @Test + public void justSeconds() { + Maybe.just(1) + .timestamp(TimeUnit.SECONDS) + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void justScheduler() { + Maybe.just(1) + .timestamp(Schedulers.single()) + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void justSecondsScheduler() { + Maybe.just(1) + .timestamp(TimeUnit.SECONDS, Schedulers.single()) + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeMaybe(m -> m.timestamp()); + } + + @Test + public void dispose() { + TestHelper.checkDisposed(MaybeSubject.create().timestamp()); + } + + @Test + public void timeInfo() { + TestScheduler scheduler = new TestScheduler(); + + MaybeSubject ms = MaybeSubject.create(); + + TestObserver> to = ms + .timestamp(scheduler) + .test(); + + scheduler.advanceTimeBy(1000, TimeUnit.MILLISECONDS); + + ms.onSuccess(1); + + to.assertResult(new Timed<>(1, 1000L, TimeUnit.MILLISECONDS)); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToCompletableTest.java index 52b44e5f989..4bae2cc98f2 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToFlowableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToFlowableTest.java index 77d098c0ce7..66e94da8d0e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToFlowableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToFlowableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToFutureTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToFutureTest.java new file mode 100644 index 00000000000..b36a299cd46 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToFutureTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.maybe; + +import static org.junit.Assert.*; + +import java.util.concurrent.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.subjects.MaybeSubject; + +public class MaybeToFutureTest extends RxJavaTest { + + @Test + public void success() throws Exception { + assertEquals((Integer)1, Maybe.just(1) + .subscribeOn(Schedulers.computation()) + .toFuture() + .get()); + } + + @Test + public void empty() throws Exception { + assertNull(Maybe.empty() + .subscribeOn(Schedulers.computation()) + .toFuture() + .get()); + } + + @Test + public void error() throws InterruptedException { + try { + Maybe.error(new TestException()) + .subscribeOn(Schedulers.computation()) + .toFuture() + .get(); + + fail("Should have thrown!"); + } catch (ExecutionException ex) { + assertTrue("" + ex.getCause(), ex.getCause() instanceof TestException); + } + } + + @Test + public void cancel() { + MaybeSubject ms = MaybeSubject.create(); + + Future f = ms.toFuture(); + + assertTrue(ms.hasObservers()); + + f.cancel(true); + + assertFalse(ms.hasObservers()); + } + + @Test + public void cancel2() { + MaybeSubject ms = MaybeSubject.create(); + + Future f = ms.toFuture(); + + assertTrue(ms.hasObservers()); + + f.cancel(false); + + assertFalse(ms.hasObservers()); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToObservableTest.java index c201bf20f8c..67472037237 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToSingleTest.java index 9d641c9505b..1ee84470f2c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeToSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUnsubscribeOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUnsubscribeOnTest.java index 1e2d7001361..3159fb411e1 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUnsubscribeOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUnsubscribeOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUsingTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUsingTest.java index c9ff65e09ab..0f083c93d25 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUsingTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeUsingTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -481,6 +481,7 @@ public void run() { } @Test + @SuppressUndeliverable public void errorDisposeRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipArrayTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipArrayTest.java index c685e79cae0..2cbf8e42633 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipArrayTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipArrayTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,17 +15,21 @@ import static org.junit.Assert.*; -import java.util.List; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.subjects.MaybeSubject; import io.reactivex.rxjava3.testsupport.TestHelper; public class MaybeZipArrayTest extends RxJavaTest { @@ -168,4 +172,70 @@ public void singleSourceZipperReturnsNull() { .to(TestHelper.testConsumer()) .assertFailureAndMessage(NullPointerException.class, "The zipper returned a null value"); } + + @Test + public void dispose2() { + TestHelper.checkDisposed(Maybe.zipArray(v -> v, MaybeSubject.create(), MaybeSubject.create())); + } + + @Test + public void bothComplete() { + AtomicReference> ref1 = new AtomicReference<>(); + AtomicReference> ref2 = new AtomicReference<>(); + + Maybe m1 = new Maybe() { + @Override + protected void subscribeActual(@NonNull MaybeObserver observer) { + ref1.set(observer); + } + }; + Maybe m2 = new Maybe() { + @Override + protected void subscribeActual(@NonNull MaybeObserver observer) { + ref2.set(observer); + } + }; + + TestObserver to = Maybe.zipArray(v -> v, m1, m2) + .test(); + + ref1.get().onSubscribe(Disposable.empty()); + ref2.get().onSubscribe(Disposable.empty()); + + ref1.get().onComplete(); + ref2.get().onComplete(); + + to.assertResult(); + } + + @Test + public void bothSucceed() { + Maybe.zipArray(v -> Arrays.asList(v), Maybe.just(1), Maybe.just(2)) + .test() + .assertResult(Arrays.asList(1, 2)); + } + + @Test + public void oneSourceOnly() { + Maybe.zipArray(v -> Arrays.asList(v), Maybe.just(1)) + .test() + .assertResult(Arrays.asList(1)); + } + + @Test + public void onSuccessAfterDispose() { + AtomicReference> emitter = new AtomicReference<>(); + + TestObserver> to = Maybe.zipArray(Arrays::asList, + (MaybeSource)o -> emitter.set(o), Maybe.never()) + .test(); + + emitter.get().onSubscribe(Disposable.empty()); + + to.dispose(); + + emitter.get().onSuccess(1); + + to.assertEmpty(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipIterableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipIterableTest.java index 4f6e07f00a8..2d60c22157c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipIterableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/maybe/MaybeZipIterableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenObservableTest.java index 9c8dfa8754c..a1e087bdf2f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenPublisherTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenPublisherTest.java index 9c0a498db59..bd9c9aa2d9d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenPublisherTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/CompletableAndThenPublisherTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapCompletableTest.java index 28c90619bbb..44acad42b12 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -28,7 +28,7 @@ import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.subjects.CompletableSubject; import io.reactivex.rxjava3.testsupport.*; @@ -66,6 +66,14 @@ public void simpleLongPrefetch() { .assertResult(); } + @Test + public void simpleLongPrefetchHidden() { + Flowable.range(1, 1024).hide() + .concatMapCompletable(Functions.justFunction(Completable.complete()), 32) + .test() + .assertResult(); + } + @Test public void mainError() { Flowable.error(new TestException()) @@ -277,7 +285,7 @@ protected void subscribeActual(Subscriber s) { Functions.justFunction(Completable.never()), 1 ) .test() - .assertFailure(MissingBackpressureException.class); + .assertFailure(QueueOverflowException.class); TestHelper.assertUndeliverable(errors, 0, TestException.class); } finally { @@ -431,4 +439,54 @@ public Completable apply(Integer v) throws Throwable { } }); } + + @Test + public void basicNonFused() { + Flowable.range(1, 5).hide() + .concatMapCompletable(v -> Completable.complete().hide()) + .test() + .assertResult(); + } + + @Test + public void basicSyncFused() { + Flowable.range(1, 5) + .concatMapCompletable(v -> Completable.complete().hide()) + .test() + .assertResult(); + } + + @Test + public void basicAsyncFused() { + UnicastProcessor up = UnicastProcessor.create(); + TestHelper.emit(up, 1, 2, 3, 4, 5); + + up + .concatMapCompletable(v -> Completable.complete().hide()) + .test() + .assertResult(); + } + + @Test + public void basicFusionRejected() { + TestHelper.rejectFlowableFusion() + .concatMapCompletable(v -> Completable.complete().hide()) + .test() + .assertEmpty(); + } + + @Test + public void fusedPollCrash() { + Flowable.range(1, 5) + .map(v -> { + if (v == 3) { + throw new TestException(); + } + return v; + }) + .compose(TestHelper.flowableStripBoundary()) + .concatMapCompletable(v -> Completable.complete().hide()) + .test() + .assertFailure(TestException.class); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapMaybeTest.java index 8a60f6c367d..12b61a5e8cd 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapMaybeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapMaybeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,11 +19,11 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; -import io.reactivex.rxjava3.disposables.Disposable; import org.junit.Test; import org.reactivestreams.Subscriber; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.functions.Functions; @@ -31,7 +31,7 @@ import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.internal.util.ErrorMode; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subjects.MaybeSubject; import io.reactivex.rxjava3.subscribers.TestSubscriber; @@ -54,15 +54,19 @@ public MaybeSource apply(Integer v) } @Test - public void simpleLong() { + public void simpleLongPrefetch() { Flowable.range(1, 1024) - .concatMapMaybe(new Function>() { - @Override - public MaybeSource apply(Integer v) - throws Exception { - return Maybe.just(v); - } - }, 32) + .concatMapMaybe(Maybe::just, 32) + .test() + .assertValueCount(1024) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void simpleLongPrefetchHidden() { + Flowable.range(1, 1024).hide() + .concatMapMaybe(Maybe::just, 32) .test() .assertValueCount(1024) .assertNoErrors() @@ -245,7 +249,7 @@ protected void subscribeActual(Subscriber s) { Functions.justFunction(Maybe.never()), 1 ) .test() - .assertFailure(MissingBackpressureException.class); + .assertFailure(QueueOverflowException.class); TestHelper.assertUndeliverable(errors, 0, TestException.class); } finally { @@ -464,4 +468,54 @@ public Maybe apply(Integer v) throws Throwable { } }); } + + @Test + public void basicNonFused() { + Flowable.range(1, 5).hide() + .concatMapMaybe(v -> Maybe.just(v).hide()) + .test() + .assertResult(1, 2, 3, 4, 5); + } + + @Test + public void basicSyncFused() { + Flowable.range(1, 5) + .concatMapMaybe(v -> Maybe.just(v).hide()) + .test() + .assertResult(1, 2, 3, 4, 5); + } + + @Test + public void basicAsyncFused() { + UnicastProcessor up = UnicastProcessor.create(); + TestHelper.emit(up, 1, 2, 3, 4, 5); + + up + .concatMapMaybe(v -> Maybe.just(v).hide()) + .test() + .assertResult(1, 2, 3, 4, 5); + } + + @Test + public void basicFusionRejected() { + TestHelper.rejectFlowableFusion() + .concatMapMaybe(v -> Maybe.just(v).hide()) + .test() + .assertEmpty(); + } + + @Test + public void fusedPollCrash() { + Flowable.range(1, 5) + .map(v -> { + if (v == 3) { + throw new TestException(); + } + return v; + }) + .compose(TestHelper.flowableStripBoundary()) + .concatMapMaybe(v -> Maybe.just(v).hide()) + .test() + .assertFailure(TestException.class, 1, 2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapSingleTest.java index a2e5d73c093..60cb2f5de0b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableConcatMapSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,7 +30,7 @@ import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.internal.util.ErrorMode; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.subjects.SingleSubject; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; @@ -52,15 +52,19 @@ public SingleSource apply(Integer v) } @Test - public void simpleLong() { + public void simpleLongPrefetch() { Flowable.range(1, 1024) - .concatMapSingle(new Function>() { - @Override - public SingleSource apply(Integer v) - throws Exception { - return Single.just(v); - } - }, 32) + .concatMapSingle(Single::just, 32) + .test() + .assertValueCount(1024) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void simpleLongPrefetchHidden() { + Flowable.range(1, 1024).hide() + .concatMapSingle(Single::just, 32) .test() .assertValueCount(1024) .assertNoErrors() @@ -163,7 +167,7 @@ protected void subscribeActual(Subscriber s) { Functions.justFunction(Single.never()), 1 ) .test() - .assertFailure(MissingBackpressureException.class); + .assertFailure(QueueOverflowException.class); TestHelper.assertUndeliverable(errors, 0, TestException.class); } finally { @@ -382,4 +386,54 @@ public Single apply(Integer v) throws Throwable { } }); } + + @Test + public void basicNonFused() { + Flowable.range(1, 5).hide() + .concatMapSingle(v -> Single.just(v).hide()) + .test() + .assertResult(1, 2, 3, 4, 5); + } + + @Test + public void basicSyncFused() { + Flowable.range(1, 5) + .concatMapSingle(v -> Single.just(v).hide()) + .test() + .assertResult(1, 2, 3, 4, 5); + } + + @Test + public void basicAsyncFused() { + UnicastProcessor up = UnicastProcessor.create(); + TestHelper.emit(up, 1, 2, 3, 4, 5); + + up + .concatMapSingle(v -> Single.just(v).hide()) + .test() + .assertResult(1, 2, 3, 4, 5); + } + + @Test + public void basicFusionRejected() { + TestHelper.rejectFlowableFusion() + .concatMapSingle(v -> Single.just(v).hide()) + .test() + .assertEmpty(); + } + + @Test + public void fusedPollCrash() { + Flowable.range(1, 5) + .map(v -> { + if (v == 3) { + throw new TestException(); + } + return v; + }) + .compose(TestHelper.flowableStripBoundary()) + .concatMapSingle(v -> Single.just(v).hide()) + .test() + .assertFailure(TestException.class, 1, 2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapCompletableTest.java index bf18f90b056..cf2065cc72b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapMaybeTest.java index 8fd4b55d6f4..1ace07440fc 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapMaybeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapMaybeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingleTest.java index a28413ab42f..cd4d64a9eb8 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/FlowableSwitchMapSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapObservableTest.java index 0b268e8d882..f91b5c6582c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapPublisherTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapPublisherTest.java index b7853ccac01..96948b05dc4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapPublisherTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/MaybeFlatMapPublisherTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapCompletableTest.java index 540e0828afe..e69e3e0ee50 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -474,4 +474,54 @@ public Completable apply(Integer v) throws Throwable { } }); } + + @Test + public void basicNonFused() { + Observable.range(1, 5).hide() + .concatMapCompletable(v -> Completable.complete().hide()) + .test() + .assertResult(); + } + + @Test + public void basicSyncFused() { + Observable.range(1, 5) + .concatMapCompletable(v -> Completable.complete().hide()) + .test() + .assertResult(); + } + + @Test + public void basicAsyncFused() { + UnicastSubject us = UnicastSubject.create(); + TestHelper.emit(us, 1, 2, 3, 4, 5); + + us + .concatMapCompletable(v -> Completable.complete().hide()) + .test() + .assertResult(); + } + + @Test + public void basicFusionRejected() { + TestHelper.rejectObservableFusion() + .concatMapCompletable(v -> Completable.complete().hide()) + .test() + .assertEmpty(); + } + + @Test + public void fusedPollCrash() { + Observable.range(1, 5) + .map(v -> { + if (v == 3) { + throw new TestException(); + } + return v; + }) + .compose(TestHelper.observableStripBoundary()) + .concatMapCompletable(v -> Completable.complete().hide()) + .test() + .assertFailure(TestException.class); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapMaybeTest.java index 323cbc32701..0dcbd274080 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapMaybeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapMaybeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -485,4 +485,54 @@ public Maybe apply(Integer v) throws Throwable { } }); } + + @Test + public void basicNonFused() { + Observable.range(1, 5).hide() + .concatMapMaybe(v -> Maybe.just(v).hide()) + .test() + .assertResult(1, 2, 3, 4, 5); + } + + @Test + public void basicSyncFused() { + Observable.range(1, 5) + .concatMapMaybe(v -> Maybe.just(v).hide()) + .test() + .assertResult(1, 2, 3, 4, 5); + } + + @Test + public void basicAsyncFused() { + UnicastSubject us = UnicastSubject.create(); + TestHelper.emit(us, 1, 2, 3, 4, 5); + + us + .concatMapMaybe(v -> Maybe.just(v).hide()) + .test() + .assertResult(1, 2, 3, 4, 5); + } + + @Test + public void basicFusionRejected() { + TestHelper.rejectObservableFusion() + .concatMapMaybe(v -> Maybe.just(v).hide()) + .test() + .assertEmpty(); + } + + @Test + public void fusedPollCrash() { + Observable.range(1, 5) + .map(v -> { + if (v == 3) { + throw new TestException(); + } + return v; + }) + .compose(TestHelper.observableStripBoundary()) + .concatMapMaybe(v -> Maybe.just(v).hide()) + .test() + .assertFailure(TestException.class, 1, 2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapSingleTest.java index 90f15ac2509..9f70b4addf7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableConcatMapSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -425,4 +425,54 @@ public Single apply(Integer v) throws Throwable { } }); } + + @Test + public void basicNonFused() { + Observable.range(1, 5).hide() + .concatMapSingle(v -> Single.just(v).hide()) + .test() + .assertResult(1, 2, 3, 4, 5); + } + + @Test + public void basicSyncFused() { + Observable.range(1, 5) + .concatMapSingle(v -> Single.just(v).hide()) + .test() + .assertResult(1, 2, 3, 4, 5); + } + + @Test + public void basicAsyncFused() { + UnicastSubject us = UnicastSubject.create(); + TestHelper.emit(us, 1, 2, 3, 4, 5); + + us + .concatMapSingle(v -> Single.just(v).hide()) + .test() + .assertResult(1, 2, 3, 4, 5); + } + + @Test + public void basicFusionRejected() { + TestHelper.rejectObservableFusion() + .concatMapSingle(v -> Single.just(v).hide()) + .test() + .assertEmpty(); + } + + @Test + public void fusedPollCrash() { + Observable.range(1, 5) + .map(v -> { + if (v == 3) { + throw new TestException(); + } + return v; + }) + .compose(TestHelper.observableStripBoundary()) + .concatMapSingle(v -> Single.just(v).hide()) + .test() + .assertFailure(TestException.class, 1, 2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapCompletableTest.java index 33ce7c27dac..0efeb6f676a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapMaybeTest.java index 865544b22a6..b2eabdd96fe 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapMaybeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapMaybeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingleTest.java index d5de085a1e1..a98afae4de9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ObservableSwitchMapSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ScalarXMapZHelperTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ScalarXMapZHelperTest.java index 8a8e745c8bf..2ac6eed7d3b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ScalarXMapZHelperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/ScalarXMapZHelperTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/SingleFlatMapObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/SingleFlatMapObservableTest.java index 3f9fcb74dee..a002620b6aa 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/SingleFlatMapObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/mixed/SingleFlatMapObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/AbstractObservableWithUpstreamTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/AbstractObservableWithUpstreamTest.java index b578dcb8f6c..5d49cd8b66a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/AbstractObservableWithUpstreamTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/AbstractObservableWithUpstreamTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableLatestTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableLatestTest.java index ef8e23ba215..feac576be73 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableLatestTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableLatestTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableMostRecentTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableMostRecentTest.java index 6ffd920f246..ccf611bbd4a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableMostRecentTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableMostRecentTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,10 +27,6 @@ import io.reactivex.rxjava3.subjects.*; public class BlockingObservableMostRecentTest extends RxJavaTest { - @Test - public void mostRecentNull() { - assertNull(Observable.never().blockingMostRecent(null).iterator().next()); - } static Iterable mostRecent(Observable source, T initialValue) { return source.blockingMostRecent(initialValue); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableNextTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableNextTest.java index 357d512e9b4..8274e9f9e31 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableNextTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableNextTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -227,8 +227,8 @@ public void nextWithCallingHasNextMultipleTimes() { /** * Confirm that no buffering or blocking of the Observable onNext calls occurs and it just grabs the next emitted value. - *

- * This results in output such as => a: 1 b: 2 c: 89 + *

+ * This results in output such as {@code => a: 1 b: 2 c: 89} * * @throws Throwable some method call is declared throws */ diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableToFutureTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableToFutureTest.java index bca24503c1a..dacf9715961 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableToFutureTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableToFutureTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import static org.junit.Assert.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableToIteratorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableToIteratorTest.java index 4b6e2bc5cd6..684eefbf615 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableToIteratorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/BlockingObservableToIteratorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,7 +23,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.internal.operators.observable.BlockingObservableIterable.BlockingObservableIterator; import io.reactivex.rxjava3.schedulers.Schedulers; @@ -131,4 +131,13 @@ public void run() { assertFalse(it.hasNext()); } + + @Test(expected = TestException.class) + public void errorAfterDispose() { + Iterator it = Observable.error(new TestException()).blockingIterable().iterator(); + + ((Disposable)it).dispose(); + + it.hasNext(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/Burst.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/Burst.java index 2bed4358792..46b5df42f32 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/Burst.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/Burst.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import java.util.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAllTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAllTest.java index 293607d66bc..fba37cb9f9b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAllTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAllTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -364,4 +364,14 @@ public boolean test(Integer v) throws Exception { RxJavaPlugins.reset(); } } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeObservableToSingle(o -> o.all(v -> true)); + } + + @Test + public void doubleOnSubscribeObservable() { + TestHelper.checkDoubleOnSubscribeObservable(o -> o.all(v -> true).toObservable()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAmbTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAmbTest.java index 4948f1a13d1..5ec9129d9f7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAmbTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAmbTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -235,7 +235,8 @@ public void ambArraySingleElement() { @Test public void manySources() { - Observable[] a = new Observable[32]; + @SuppressWarnings("unchecked") + Observable[] a = new Observable[32]; Arrays.fill(a, Observable.never()); a[31] = Observable.just(1); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAnyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAnyTest.java index 35faf30c196..cb85603fa18 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAnyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAnyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAutoConnectTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAutoConnectTest.java index 5ed5b3124e6..16128ff1954 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAutoConnectTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableAutoConnectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBlockingTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBlockingTest.java index a2d98545695..05fbb5a94ca 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBlockingTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBlockingTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferTest.java index af4e7a94150..7085720f013 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -37,7 +37,7 @@ import io.reactivex.rxjava3.observers.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.*; -import io.reactivex.rxjava3.subjects.PublishSubject; +import io.reactivex.rxjava3.subjects.*; import io.reactivex.rxjava3.testsupport.TestHelper; public class ObservableBufferTest extends RxJavaTest { @@ -1278,9 +1278,9 @@ public Integer apply(Integer integer, Long aLong) { } }) .buffer(Observable.interval(0, 200, TimeUnit.MILLISECONDS), - new Function>() { + new Function>() { @Override - public Observable apply(Long a) { + public Observable apply(Long a) { return Observable.just(a).delay(100, TimeUnit.MILLISECONDS); } }) @@ -1301,9 +1301,9 @@ public Integer apply(Integer integer, Long aLong) { } }) .buffer(Observable.interval(0, 100, TimeUnit.MILLISECONDS), - new Function>() { + new Function>() { @Override - public Observable apply(Long a) { + public Observable apply(Long a) { return Observable.just(a).delay(200, TimeUnit.MILLISECONDS); } }) @@ -1788,4 +1788,31 @@ public List get() throws Exception { .assertFailure(TestException.class) ; } + + @Test + public void timedUnboundedCancelUpfront() { + Observable.never() + .buffer(1, TimeUnit.SECONDS) + .test(true) + .assertEmpty(); + } + + @Test + public void boundaryCloseCompleteRace() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + BehaviorSubject bs = BehaviorSubject.createDefault(1); + PublishSubject ps = PublishSubject.create(); + + TestObserver> to = bs + .buffer(BehaviorSubject.createDefault(0), v -> ps) + .test(); + + TestHelper.race( + () -> bs.onComplete(), + () -> ps.onComplete() + ); + + to.assertResult(Arrays.asList(1)); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferUntilSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferUntilSubscriberTest.java index 6d49272de26..eb67fee441c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferUntilSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableBufferUntilSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCacheTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCacheTest.java index 8f4440e41b9..74d17c062b2 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCacheTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCacheTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,16 +16,21 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.MemoryUsage; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; -import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.observables.ConnectableObservable; import org.junit.Test; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.observers.TestObserver; @@ -341,4 +346,66 @@ public Object call() throws Exception { assertEquals(1, call.get()); } + + @Test + public void addRemoveRace() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + Observable o = Observable.never().cache(); + + TestObserver to = o.test(); + + TestHelper.race( + () -> to.dispose(), + () -> o.test() + ); + } + } + + @Test + public void valuesAreReclaimable() throws Exception { + ConnectableObservable source = + Observable.range(0, 200) + .map($ -> new byte[1024 * 1024]) + .publish(); + + System.out.println("Bounded Replay Leak check: Wait before GC"); + Thread.sleep(1000); + + System.out.println("Bounded Replay Leak check: GC"); + System.gc(); + + Thread.sleep(500); + + final MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); + MemoryUsage memHeap = memoryMXBean.getHeapMemoryUsage(); + long initial = memHeap.getUsed(); + + System.out.printf("Bounded Replay Leak check: Starting: %.3f MB%n", initial / 1024.0 / 1024.0); + + final AtomicLong after = new AtomicLong(); + + source.cache().lastElement().subscribe(new Consumer() { + @Override + public void accept(byte[] v) throws Exception { + System.out.println("Bounded Replay Leak check: Wait before GC 2"); + Thread.sleep(1000); + + System.out.println("Bounded Replay Leak check: GC 2"); + System.gc(); + + Thread.sleep(500); + + after.set(memoryMXBean.getHeapMemoryUsage().getUsed()); + } + }); + + source.connect(); + + System.out.printf("Bounded Replay Leak check: After: %.3f MB%n", after.get() / 1024.0 / 1024.0); + + if (initial + 100 * 1024 * 1024 < after.get()) { + fail("Bounded Replay Leak check: Memory leak detected: " + (initial / 1024.0 / 1024.0) + + " -> " + after.get() / 1024.0 / 1024.0); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCastTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCastTest.java index 52576fb9b9f..83fdb4b1e53 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCastTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCastTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCollectTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCollectTest.java index 0568b0d4749..92867c2d795 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCollectTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCollectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCombineLatestTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCombineLatestTest.java index 3096cdabd73..2b966ec29ca 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCombineLatestTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCombineLatestTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,7 +19,7 @@ import java.util.*; import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.*; import org.junit.Test; import org.mockito.*; @@ -789,7 +789,7 @@ public Object apply(Object[] a) throws Exception { @SuppressWarnings("unchecked") public void combineLatestDelayErrorArrayOfSources() { - Observable.combineLatestDelayError(new ObservableSource[] { + Observable.combineLatestArrayDelayError(new ObservableSource[] { Observable.just(1), Observable.just(2) }, new Function() { @Override @@ -805,7 +805,7 @@ public Object apply(Object[] a) throws Exception { @SuppressWarnings("unchecked") public void combineLatestDelayErrorArrayOfSourcesWithError() { - Observable.combineLatestDelayError(new ObservableSource[] { + Observable.combineLatestArrayDelayError(new ObservableSource[] { Observable.just(1), Observable.just(2).concatWith(Observable.error(new TestException())) }, new Function() { @Override @@ -856,7 +856,7 @@ public void combineLatestArrayEmpty() { @SuppressWarnings("unchecked") @Test public void combineLatestDelayErrorEmpty() { - assertSame(Observable.empty(), Observable.combineLatestDelayError(new ObservableSource[0], Functions.identity(), 16)); + assertSame(Observable.empty(), Observable.combineLatestArrayDelayError(new ObservableSource[0], Functions.identity(), 16)); } @Test @@ -923,7 +923,7 @@ public Object apply(Object a, Object b) throws Exception { @SuppressWarnings("unchecked") @Test public void errorDelayed() { - Observable.combineLatestDelayError( + Observable.combineLatestArrayDelayError( new ObservableSource[] { Observable.error(new TestException()), Observable.just(1) }, new Function() { @Override @@ -940,7 +940,7 @@ public Object apply(Object[] a) throws Exception { @SuppressWarnings("unchecked") @Test public void errorDelayed2() { - Observable.combineLatestDelayError( + Observable.combineLatestArrayDelayError( new ObservableSource[] { Observable.error(new TestException()).startWithItem(1), Observable.empty() }, new Function() { @Override @@ -1226,4 +1226,76 @@ public Integer apply(Object[] t) throws Throwable { .test() .assertResult(2); } + + @Test + public void onCompleteDisposeRace() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + + TestObserver to = new TestObserver<>(); + PublishSubject ps = PublishSubject.create(); + + Observable.combineLatest(ps, Observable.never(), (a, b) -> a) + .subscribe(to); + + TestHelper.race(() -> ps.onComplete(), () -> to.dispose()); + } + } + + @Test + public void onErrorDisposeDelayErrorRace() throws Throwable { + TestHelper.withErrorTracking(errors -> { + TestException ex = new TestException(); + + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + + TestObserverEx to = new TestObserverEx<>(); + AtomicReference> ref = new AtomicReference<>(); + Observable o = new Observable() { + @Override + public void subscribeActual(Observer observer) { + ref.set(observer); + } + }; + + Observable.combineLatestDelayError(Arrays.asList(o, Observable.never()), (a) -> a) + .subscribe(to); + + ref.get().onSubscribe(Disposable.empty()); + + TestHelper.race(() -> ref.get().onError(ex), () -> to.dispose()); + + if (to.errors().isEmpty()) { + TestHelper.assertUndeliverable(errors, 0, TestException.class); + } + } + }); + } + + @Test + public void doneButNotEmpty() { + PublishSubject ps1 = PublishSubject.create(); + PublishSubject ps2 = PublishSubject.create(); + + TestObserver to = Observable.combineLatest(ps1, ps2, (a, b) -> a + b) + .doOnNext(v -> { + if (v == 2) { + ps2.onNext(3); + ps2.onComplete(); + ps1.onComplete(); + } + }) + .test(); + + ps1.onNext(1); + ps2.onNext(1); + + to.assertResult(2, 4); + } + + @Test + public void iterableNullPublisher() { + Observable.combineLatest(Arrays.asList(Observable.never(), null), (a) -> a) + .test() + .assertFailure(NullPointerException.class); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapCompletableTest.java index 55b880a9f99..931fcd403f5 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapCompletableTest.java @@ -1,15 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. - *

+ * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at - *

+ * * http://www.apache.org/licenses/LICENSE-2.0 - *

+ * * Unless required by applicable law or agreed to in writing, software distributed under the License is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import static org.junit.Assert.assertTrue; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapEagerTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapEagerTest.java index ab4ba0273f9..1e75ff9aef8 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapEagerTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapEagerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -535,7 +535,7 @@ public void badCapacityHint() throws Exception { try { Observable.concatEager(Arrays.asList(source, source, source), 1, -99); } catch (IllegalArgumentException ex) { - assertEquals("prefetch > 0 required but it was -99", ex.getMessage()); + assertEquals("bufferSize > 0 required but it was -99", ex.getMessage()); } } @@ -547,7 +547,7 @@ public void mappingBadCapacityHint() throws Exception { try { Observable.just(source, source, source).concatMapEager((Function)Functions.identity(), 10, -99); } catch (IllegalArgumentException ex) { - assertEquals("prefetch > 0 required but it was -99", ex.getMessage()); + assertEquals("bufferSize > 0 required but it was -99", ex.getMessage()); } } @@ -1034,4 +1034,57 @@ public Observable apply(Integer v) throws Throwable { } }); } + + @Test + public void iterableDelayError() { + Observable.concatEagerDelayError(Arrays.asList( + Observable.range(1, 2), + Observable.error(new TestException()), + Observable.range(3, 3) + )) + .test() + .assertFailure(TestException.class, 1, 2, 3, 4, 5); + } + + @Test + public void iterableDelayErrorMaxConcurrency() { + Observable.concatEagerDelayError(Arrays.asList( + Observable.range(1, 2), + Observable.error(new TestException()), + Observable.range(3, 3) + ), 1, 1) + .test() + .assertFailure(TestException.class, 1, 2, 3, 4, 5); + } + + @Test + public void observerDelayError() { + Observable.concatEagerDelayError(Observable.fromArray( + Observable.range(1, 2), + Observable.error(new TestException()), + Observable.range(3, 3) + )) + .test() + .assertFailure(TestException.class, 1, 2, 3, 4, 5); + } + + @Test + public void observerDelayErrorMaxConcurrency() { + Observable.concatEagerDelayError(Observable.fromArray( + Observable.range(1, 2), + Observable.error(new TestException()), + Observable.range(3, 3) + ), 1, 1) + .test() + .assertFailure(TestException.class, 1, 2, 3, 4, 5); + } + + @Test + public void innerFusionRejected() { + Observable.just(1) + .hide() + .concatMapEager(v -> TestHelper.rejectObservableFusion()) + .test() + .assertEmpty(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapSchedulerTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapSchedulerTest.java index a82553b9a4e..f2a6ede3144 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapSchedulerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,14 +20,16 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; -import io.reactivex.rxjava3.disposables.Disposable; import org.junit.Test; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.disposables.EmptyDisposable; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.internal.schedulers.ImmediateThinScheduler; import io.reactivex.rxjava3.observers.*; @@ -305,7 +307,7 @@ public Observable apply(Integer t) throws Throwable { } @Test - public void issue2890NoStackoverflow() throws InterruptedException { + public void issue2890NoStackoverflow() throws InterruptedException, TimeoutException { final ExecutorService executor = Executors.newFixedThreadPool(2); final Scheduler sch = Schedulers.from(executor); @@ -350,7 +352,11 @@ public void onError(Throwable e) { } }); - executor.awaitTermination(20000, TimeUnit.MILLISECONDS); + long awaitTerminationTimeout = 100_000; + if (!executor.awaitTermination(awaitTerminationTimeout, TimeUnit.MILLISECONDS)) { + throw new TimeoutException("Completed " + counter.get() + "/" + n + " before timed out after " + + awaitTerminationTimeout + " milliseconds."); + } assertEquals(n, counter.get()); } @@ -1049,4 +1055,70 @@ public Observable apply(Integer v) throws Throwable { } }); } + + @Test + public void fusionRejected() { + TestObserverEx to = new TestObserverEx<>(); + + TestHelper.rejectObservableFusion() + .concatMap(v -> Observable.never(), 2, ImmediateThinScheduler.INSTANCE) + .subscribe(to); + } + + @Test + public void fusionRejectedDelayErrorr() { + TestObserverEx to = new TestObserverEx<>(); + + TestHelper.rejectObservableFusion() + .concatMapDelayError(v -> Observable.never(), true, 2, ImmediateThinScheduler.INSTANCE) + .subscribe(to); + } + + @Test + public void scalarInnerJustDisposeDelayError() { + TestObserver to = new TestObserver<>(); + + Observable.just(1) + .hide() + .concatMapDelayError(v -> Observable.fromCallable(() -> { + to.dispose(); + return 1; + }), true, 2, ImmediateThinScheduler.INSTANCE) + .subscribe(to); + + to.assertEmpty(); + } + + static final class EmptyDisposingObservable extends Observable + implements Supplier { + final TestObserver to; + EmptyDisposingObservable(TestObserver to) { + this.to = to; + } + + @Override + protected void subscribeActual(@NonNull Observer observer) { + EmptyDisposable.complete(observer); + } + + @Override + public @NonNull Object get() throws Throwable { + to.dispose(); + return null; + } + } + + @Test + public void scalarInnerEmptyDisposeDelayError() { + TestObserver to = new TestObserver<>(); + + Observable.just(1) + .hide() + .concatMapDelayError(v -> new EmptyDisposingObservable(to), + true, 2, ImmediateThinScheduler.INSTANCE + ) + .subscribe(to); + + to.assertEmpty(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapTest.java index a5d2a6aa4cc..8fb29f2eb49 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,10 +22,11 @@ import org.junit.Test; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.internal.operators.observable.ObservableConcatMapSchedulerTest.EmptyDisposingObservable; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.subjects.*; @@ -565,4 +566,108 @@ public Observable apply(Integer v) throws Throwable { } }); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeObservable(o -> o.concatMap(v -> Observable.never())); + } + + @Test + public void doubleOnSubscribeDelayError() { + TestHelper.checkDoubleOnSubscribeObservable(o -> o.concatMapDelayError(v -> Observable.never())); + } + + @Test + public void scalarXMap() { + Observable.fromCallable(() -> 1) + .concatMap(v -> Observable.just(2).hide()) + .test() + .assertResult(2); + } + + @Test + public void rejectedFusion() { + TestHelper.rejectObservableFusion() + .concatMap(v -> Observable.never()) + .test(); + } + + @Test + public void rejectedFusionDelayError() { + TestHelper.rejectObservableFusion() + .concatMapDelayError(v -> Observable.never()) + .test(); + } + + @Test + public void asyncFusedDelayError() { + UnicastSubject uc = UnicastSubject.create(); + + TestObserver to = uc.concatMapDelayError(v -> Observable.just(v).hide()) + .test(); + + uc.onNext(1); + uc.onComplete(); + + to.assertResult(1); + } + + @Test + public void scalarInnerJustDelayError() { + Observable.just(1) + .hide() + .concatMapDelayError(v -> Observable.just(v)) + .test() + .assertResult(1); + } + + @Test + public void scalarInnerEmptyDelayError() { + Observable.just(1) + .hide() + .concatMapDelayError(v -> Observable.empty()) + .test() + .assertResult(); + } + + @Test + public void scalarInnerJustDisposeDelayError() { + TestObserver to = new TestObserver<>(); + + Observable.just(1) + .hide() + .concatMapDelayError(v -> Observable.fromCallable(() -> { + to.dispose(); + return 1; + })) + .subscribe(to); + + to.assertEmpty(); + } + + @Test + public void scalarInnerEmptyDisposeDelayError() { + TestObserver to = new TestObserver<>(); + + Observable.just(1) + .hide() + .concatMapDelayError(v -> new EmptyDisposingObservable(to)) + .subscribe(to); + + to.assertEmpty(); + } + + @Test + public void delayErrorInnerActive() { + PublishSubject ps = PublishSubject.create(); + + TestObserver to = Observable.range(1, 5) + .hide() + .concatMapDelayError(v -> ps) + .test(); + + ps.onComplete(); + + to.assertResult(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatTest.java index b1c42a11759..d14f803ee9c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -683,7 +683,7 @@ public void subscribe(Observer observer) { } @Test - public void issue2890NoStackoverflow() throws InterruptedException { + public void issue2890NoStackoverflow() throws InterruptedException, TimeoutException { final ExecutorService executor = Executors.newFixedThreadPool(2); final Scheduler sch = Schedulers.from(executor); @@ -728,7 +728,11 @@ public void onError(Throwable e) { } }); - executor.awaitTermination(20000, TimeUnit.MILLISECONDS); + long awaitTerminationTimeout = 100_000; + if (!executor.awaitTermination(awaitTerminationTimeout, TimeUnit.MILLISECONDS)) { + throw new TimeoutException("Completed " + counter.get() + "/" + n + " before timed out after " + + awaitTerminationTimeout + " milliseconds."); + } assertEquals(n, counter.get()); } @@ -879,7 +883,7 @@ public void concatMapIterableBufferSize() { public Iterable apply(Integer v) throws Exception { return Arrays.asList(1, 2, 3, 4, 5); } - }, 1) + }) .test() .assertResult(1, 2, 3, 4, 5, 1, 2, 3, 4, 5); } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithCompletableTest.java index fc2a8b8531c..5e0d878a345 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithMaybeTest.java index 16ba059b8b6..6c70e75a9d0 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithMaybeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithMaybeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithSingleTest.java index 2d05b58c2d6..8ac2519c3c6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableConcatWithSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCountTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCountTest.java index 4207fee66f0..13905028165 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCountTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCountTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCreateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCreateTest.java index f5be343b40b..0b96fae6aaf 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCreateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableCreateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,24 +17,23 @@ import java.io.IOException; import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Cancellable; +import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.testsupport.*; public class ObservableCreateTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void nullArgument() { - Observable.create(null); - } - @Test + @SuppressUndeliverable public void basic() { final Disposable d = Disposable.empty(); @@ -60,6 +59,7 @@ public void subscribe(ObservableEmitter e) throws Exception { } @Test + @SuppressUndeliverable public void basicWithCancellable() { final Disposable d1 = Disposable.empty(); final Disposable d2 = Disposable.empty(); @@ -93,6 +93,7 @@ public void cancel() throws Exception { } @Test + @SuppressUndeliverable public void basicWithError() { final Disposable d = Disposable.empty(); @@ -117,6 +118,7 @@ public void subscribe(ObservableEmitter e) throws Exception { } @Test + @SuppressUndeliverable public void basicSerialized() { final Disposable d = Disposable.empty(); @@ -144,6 +146,7 @@ public void subscribe(ObservableEmitter e) throws Exception { } @Test + @SuppressUndeliverable public void basicWithErrorSerialized() { final Disposable d = Disposable.empty(); @@ -211,6 +214,7 @@ public void unsafeWithObservable() { } @Test + @SuppressUndeliverable public void createNullValue() { final Throwable[] error = { null }; @@ -234,6 +238,7 @@ public void subscribe(ObservableEmitter e) throws Exception { } @Test + @SuppressUndeliverable public void createNullValueSerialized() { final Throwable[] error = { null }; @@ -659,4 +664,96 @@ public void subscribe(ObservableEmitter emitter) throws Exception { } }).test().assertEmpty(); } + + @Test + public void emptySerialized() { + Observable.create(emitter -> emitter.serialize().onComplete()) + .test() + .assertResult(); + } + + @Test + public void serializedDisposedBeforeOnNext() { + TestObserver to = new TestObserver<>(); + + Observable.create(emitter -> { + to.dispose(); + emitter.serialize().onNext(1); + }) + .subscribe(to); + + to.assertEmpty(); + } + + @Test + public void serializedOnNextAfterComplete() { + TestObserver to = new TestObserver<>(); + + Observable.create(emitter -> { + emitter = emitter.serialize(); + + emitter.onComplete(); + emitter.onNext(1); + }) + .subscribe(to); + + to.assertResult(); + } + + @Test + public void serializedEnqueueAndDrainRace() throws Throwable { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + TestObserver to = new TestObserver<>(); + AtomicReference> ref = new AtomicReference<>(); + + CountDownLatch cdl = new CountDownLatch(1); + + Observable.create(emitter -> { + emitter = emitter.serialize(); + ref.set(emitter); + emitter.onNext(1); + }) + .doOnNext(v -> { + if (v == 1) { + TestHelper.raceOther(() -> { + ref.get().onNext(2); + }, cdl); + ref.get().onNext(3); + } + }) + .subscribe(to); + + cdl.await(); + + to.assertValueCount(3); + } + } + + @Test + public void serializedDrainDoneButNotEmpty() throws Throwable { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + TestObserver to = new TestObserver<>(); + AtomicReference> ref = new AtomicReference<>(); + + CountDownLatch cdl = new CountDownLatch(1); + + Observable.create(emitter -> { + emitter = emitter.serialize(); + ref.set(emitter); + emitter.onNext(1); + }) + .doOnNext(v -> { + if (v == 1) { + TestHelper.raceOther(() -> { + ref.get().onNext(2); + ref.get().onComplete(); + }, cdl); + ref.get().onNext(3); + } + }) + .subscribe(to); + + cdl.await(); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDebounceTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDebounceTest.java index d59431a6775..fc4e7d8478d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDebounceTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDebounceTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,6 +21,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import io.reactivex.rxjava3.functions.Action; import org.junit.*; import org.mockito.InOrder; import org.reactivestreams.Publisher; @@ -50,6 +51,76 @@ public void before() { innerScheduler = scheduler.createWorker(); } + @Test + public void debounceWithOnDroppedCallbackWithEx() throws Throwable { + Observable source = Observable.unsafeCreate(new ObservableSource() { + @Override + public void subscribe(Observer observer) { + observer.onSubscribe(Disposable.empty()); + publishNext(observer, 100, "one"); // Should be skipped since "two" will arrive before the timeout expires. + publishNext(observer, 400, "two"); // Should be published since "three" will arrive after the timeout expires. + publishNext(observer, 900, "three"); // Should be skipped since onComplete will arrive before the timeout expires. + publishNext(observer, 999, "four"); // Should be skipped since onComplete will arrive before the timeout expires. + publishCompleted(observer, 1000); // Should be published as soon as the timeout expires. + } + }); + + Action whenDisposed = mock(Action.class); + Observable sampled = source + .doOnDispose(whenDisposed) + .debounce(400, TimeUnit.MILLISECONDS, scheduler, e -> { + if ("three".equals(e)) { + throw new TestException("forced"); + } + }); + sampled.subscribe(observer); + + scheduler.advanceTimeTo(0, TimeUnit.MILLISECONDS); + InOrder inOrder = inOrder(observer); + // must go to 800 since it must be 400 after when two is sent, which is at 400 + scheduler.advanceTimeTo(800, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("two"); + scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onError(any(TestException.class)); + inOrder.verify(observer, never()).onNext("three"); + inOrder.verify(observer, never()).onNext("four"); + inOrder.verify(observer, never()).onComplete(); + inOrder.verifyNoMoreInteractions(); + verify(whenDisposed).run(); + } + + @Test + public void debounceWithOnDroppedCallback() { + Observable source = Observable.unsafeCreate(new ObservableSource() { + @Override + public void subscribe(Observer observer) { + observer.onSubscribe(Disposable.empty()); + publishNext(observer, 100, "one"); // Should be skipped since "two" will arrive before the timeout expires. + publishNext(observer, 400, "two"); // Should be published since "three" will arrive after the timeout expires. + publishNext(observer, 900, "three"); // Should be skipped since onComplete will arrive before the timeout expires. + publishNext(observer, 999, "four"); // Should be skipped since onComplete will arrive before the timeout expires. + publishCompleted(observer, 1000); // Should be published as soon as the timeout expires. + } + }); + + Observer drops = TestHelper.mockObserver(); + InOrder inOrderDrops = inOrder(drops); + Observable sampled = source.debounce(400, TimeUnit.MILLISECONDS, scheduler, drops::onNext); + sampled.subscribe(observer); + + scheduler.advanceTimeTo(0, TimeUnit.MILLISECONDS); + InOrder inOrder = inOrder(observer); + // must go to 800 since it must be 400 after when two is sent, which is at 400 + scheduler.advanceTimeTo(800, TimeUnit.MILLISECONDS); + inOrderDrops.verify(drops, times(1)).onNext("one"); + inOrder.verify(observer, times(1)).onNext("two"); + scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); + inOrderDrops.verify(drops, times(1)).onNext("three"); + inOrder.verify(observer, times(1)).onComplete(); + inOrder.verifyNoMoreInteractions(); + inOrderDrops.verifyNoMoreInteractions(); + } + @Test public void debounceWithCompleted() { Observable source = Observable.unsafeCreate(new ObservableSource() { @@ -489,7 +560,7 @@ protected void subscribeActual( public void timedLateEmit() { TestObserver to = new TestObserver<>(); DebounceTimedObserver sub = new DebounceTimedObserver<>( - to, 1, TimeUnit.SECONDS, new TestScheduler().createWorker()); + to, 1, TimeUnit.SECONDS, new TestScheduler().createWorker(), null); sub.onSubscribe(Disposable.empty()); @@ -517,4 +588,9 @@ public ObservableSource apply(Object o) { } }).subscribe(); } + + @Test + public void doubleOnSubscribeTime() { + TestHelper.checkDoubleOnSubscribeObservable(o -> o.debounce(1, TimeUnit.SECONDS)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDefaultIfEmptyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDefaultIfEmptyTest.java index 1ca00cf1b4c..7a1d66e908c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDefaultIfEmptyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDefaultIfEmptyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDeferTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDeferTest.java index 50ded2e55a9..cb919f02ff5 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDeferTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDeferTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelaySubscriptionOtherTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelaySubscriptionOtherTest.java index 93b09456ddf..02d988c2e8a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelaySubscriptionOtherTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelaySubscriptionOtherTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelayTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelayTest.java index 82b60d4701d..778d2d4e64d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelayTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDelayTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,6 +20,7 @@ import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.LockSupport; import org.junit.*; import org.mockito.InOrder; @@ -29,6 +30,7 @@ import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.disposables.SequentialDisposable; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.observers.*; import io.reactivex.rxjava3.schedulers.*; @@ -978,4 +980,37 @@ public Observable apply(Integer t) throws Exception { .to(TestHelper.testConsumer()) .assertFailureAndMessage(NullPointerException.class, "The itemDelay returned a null ObservableSource"); } -} + + @Test + public void cancelShouldPreventRandomSubsequentEmissions() { + for (int attempt = 1; attempt < 100; attempt ++) { + + SequentialDisposable disposable = new SequentialDisposable(); + ConcurrentLinkedQueue sink = new ConcurrentLinkedQueue<>(); + + disposable.replace( + Observable.range(1, 10) + .delay(1, TimeUnit.MICROSECONDS, Schedulers.computation(), true) + .doOnNext(v -> { + if (v == 1) { + Schedulers.computation().scheduleDirect(disposable::dispose); + } + sink.offer(v); + }) + .subscribe()); + + LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1)); + + Integer last = null; + + while (!sink.isEmpty()) { + Integer current = sink.poll(); + + if (last != null && last + 1 != current) { + fail("Emission hole: " + last + " -> " + current); + } + + last = current; + } + } + }} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDematerializeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDematerializeTest.java index 8c7b6017ab4..e28b71a6299 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDematerializeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDematerializeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -221,16 +221,17 @@ protected void subscribeActual(Observer> observer) } @Test + @SuppressWarnings("unchecked") public void nonNotificationInstanceAfterDispose() { - new Observable>() { + new Observable() { @Override - protected void subscribeActual(Observer> observer) { + protected void subscribeActual(Observer observer) { observer.onSubscribe(Disposable.empty()); observer.onNext(Notification.createOnComplete()); - observer.onNext(Notification.createOnNext(1)); + observer.onNext(1); } } - .dematerialize(Functions.>identity()) + .dematerialize(v -> (Notification)v) .test() .assertResult(); } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDetachTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDetachTest.java index 95cbf96f765..5e4e3d5fce0 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDetachTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDetachTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import java.lang.ref.WeakReference; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinctTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinctTest.java index 1f2614f2843..178f700db59 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinctTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinctTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -29,8 +29,9 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.util.ExceptionHelper; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.subjects.UnicastSubject; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinctUntilChangedTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinctUntilChangedTest.java index 190506aed2d..7f58ab2f892 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinctUntilChangedTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDistinctUntilChangedTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,8 +26,8 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.subjects.*; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoAfterNextTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoAfterNextTest.java index 411989a0f19..8338d2c9ec5 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoAfterNextTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoAfterNextTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,8 +24,8 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Consumer; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.subjects.UnicastSubject; import io.reactivex.rxjava3.testsupport.*; @@ -145,11 +145,6 @@ public void asyncFused() { assertEquals(Arrays.asList(-1, -2, -3, -4, -5), values); } - @Test(expected = NullPointerException.class) - public void consumerNull() { - Observable.just(1).doAfterNext(null); - } - @Test public void justConditional() { Observable.just(1) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoFinallyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoFinallyTest.java index 0cc21b8f136..3753b411275 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoFinallyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoFinallyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,8 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.*; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.subjects.UnicastSubject; import io.reactivex.rxjava3.testsupport.*; @@ -299,11 +300,6 @@ public void asyncFusedBoundaryConditional() { assertEquals(1, calls); } - @Test(expected = NullPointerException.class) - public void nullAction() { - Observable.just(1).doFinally(null); - } - @Test public void actionThrows() { List errors = TestHelper.trackPluginErrors(); @@ -524,4 +520,16 @@ public void run() throws Exception { assertEquals(Arrays.asList("onNext", "onComplete", "finally"), list); } + @Test + public void fusionRejected() { + TestObserverEx to = new TestObserverEx<>(); + to.setInitialFusionMode(QueueFuseable.ANY); + + TestHelper.rejectObservableFusion() + .doFinally(() -> { }) + .subscribeWith(to); + + to.assertFuseable() + .assertFusionMode(QueueFuseable.NONE); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnEachTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnEachTest.java index 6b8627b02bc..1f71d2b0a39 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnEachTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnEachTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -28,8 +28,8 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.subjects.UnicastSubject; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnSubscribeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnSubscribeTest.java index 5a16beda68c..f001d28ac0c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnSubscribeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnSubscribeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnUnsubscribeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnUnsubscribeTest.java index a95f372d183..5ac217725b3 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnUnsubscribeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableDoOnUnsubscribeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAtTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAtTest.java index 679915dc510..8ce5cb047c2 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAtTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableElementAtTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFilterTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFilterTest.java index 6bbb838da5d..71585b1c337 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFilterTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFilterTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,7 +23,7 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.subjects.UnicastSubject; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFinallyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFinallyTest.java index 7767ddb9fc5..9f20203ed29 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFinallyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFinallyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFirstTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFirstTest.java index e022144ce23..9129f1d0cd2 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFirstTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFirstTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapCompletableTest.java index 95baba14484..facfb084d13 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,7 +16,7 @@ import static org.junit.Assert.*; import java.util.List; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import org.junit.Test; @@ -24,8 +24,9 @@ import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subjects.PublishSubject; import io.reactivex.rxjava3.testsupport.*; @@ -506,4 +507,59 @@ public Completable apply(Integer v) throws Throwable { } }); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeObservable(o -> o.flatMapCompletable(v -> Completable.never()).toObservable()); + } + + @Test + public void doubleOnSubscribeCompletable() { + TestHelper.checkDoubleOnSubscribeObservableToCompletable(o -> o.flatMapCompletable(v -> Completable.never())); + } + + @Test + public void cancelWhileMapping() throws Throwable { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + PublishSubject ps1 = PublishSubject.create(); + + TestObserver to = new TestObserver<>(); + CountDownLatch cdl = new CountDownLatch(1); + + ps1.flatMapCompletable(v -> { + TestHelper.raceOther(() -> { + to.dispose(); + }, cdl); + return Completable.complete(); + }) + .toObservable() + .subscribe(to); + + ps1.onNext(1); + + cdl.await(); + } + } + + @Test + public void cancelWhileMappingCompletable() throws Throwable { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + PublishSubject ps1 = PublishSubject.create(); + + TestObserver to = new TestObserver<>(); + CountDownLatch cdl = new CountDownLatch(1); + + ps1.flatMapCompletable(v -> { + TestHelper.raceOther(() -> { + to.dispose(); + }, cdl); + return Completable.complete(); + }) + .subscribe(to); + + ps1.onNext(1); + + cdl.await(); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybeTest.java index a1540dcfcae..0c0d29c8e7e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapMaybeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,14 +21,14 @@ import org.junit.Test; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.Schedulers; -import io.reactivex.rxjava3.subjects.PublishSubject; +import io.reactivex.rxjava3.subjects.*; import io.reactivex.rxjava3.testsupport.*; public class ObservableFlatMapMaybeTest extends RxJavaTest { @@ -483,4 +483,64 @@ public Maybe apply(Integer v) throws Throwable { } }); } + + @Test + public void cancelWhileMapping() throws Throwable { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + PublishSubject ps1 = PublishSubject.create(); + + TestObserver to = new TestObserver<>(); + CountDownLatch cdl = new CountDownLatch(1); + + ps1.flatMapMaybe(v -> { + TestHelper.raceOther(() -> { + to.dispose(); + }, cdl); + return Maybe.just(1); + }) + .subscribe(to); + + ps1.onNext(1); + + cdl.await(); + } + } + + @Test + public void successCompleteRace() { + for (int i = 0; i < TestHelper.RACE_LONG_LOOPS; i++) { + MaybeSubject ms1 = MaybeSubject.create(); + MaybeSubject ms2 = MaybeSubject.create(); + + TestObserver to = Observable.just(1, 2) + .flatMapMaybe(v -> v == 1 ? ms1 : ms2) + .test(); + + TestHelper.race( + () -> ms1.onComplete(), + () -> ms2.onSuccess(1) + ); + + to.assertResult(1); + } + } + + @Test + public void successCompleteRace2() { + for (int i = 0; i < TestHelper.RACE_LONG_LOOPS; i++) { + MaybeSubject ms1 = MaybeSubject.create(); + MaybeSubject ms2 = MaybeSubject.create(); + + TestObserver to = Observable.just(1, 2) + .flatMapMaybe(v -> v == 1 ? ms1 : ms2) + .test(); + + TestHelper.race( + () -> ms2.onSuccess(1), + () -> ms1.onComplete() + ); + + to.assertResult(1); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingleTest.java index b990bd407cf..1fa219111be 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,14 +21,14 @@ import org.junit.Test; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.Schedulers; -import io.reactivex.rxjava3.subjects.PublishSubject; +import io.reactivex.rxjava3.subjects.*; import io.reactivex.rxjava3.testsupport.*; public class ObservableFlatMapSingleTest extends RxJavaTest { @@ -398,4 +398,69 @@ public Single apply(Integer v) throws Throwable { } }); } + + @Test + public void innerErrorOuterCompleteRace() { + TestException ex = new TestException(); + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + PublishSubject ps1 = PublishSubject.create(); + SingleSubject ps2 = SingleSubject.create(); + + TestObserver to = ps1.flatMapSingle(v -> ps2) + .test(); + + ps1.onNext(1); + + TestHelper.race( + () -> ps1.onComplete(), + () -> ps2.onError(ex) + ); + + to.assertFailure(TestException.class); + } + } + + @Test + public void cancelWhileMapping() throws Throwable { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + PublishSubject ps1 = PublishSubject.create(); + + TestObserver to = new TestObserver<>(); + CountDownLatch cdl = new CountDownLatch(1); + + ps1.flatMapSingle(v -> { + TestHelper.raceOther(() -> { + to.dispose(); + }, cdl); + return Single.just(1); + }) + .subscribe(to); + + ps1.onNext(1); + + cdl.await(); + } + } + + @Test + public void onNextDrainCancel() { + SingleSubject ss1 = SingleSubject.create(); + SingleSubject ss2 = SingleSubject.create(); + + TestObserver to = new TestObserver<>(); + + Observable.just(1, 2) + .flatMapSingle(v -> v == 1 ? ss1 : ss2) + .doOnNext(v -> { + if (v == 1) { + ss2.onSuccess(2); + to.dispose(); + } + }) + .subscribe(to); + + ss1.onSuccess(1); + + to.assertValuesOnly(1); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapTest.java index 00f2523a332..4622888628e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlatMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,16 +17,18 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; +import java.io.IOException; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; import org.junit.*; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; @@ -1079,4 +1081,187 @@ public Observable apply(Integer v) throws Throwable { } }); } + + @Test + public void mainErrorsInnerCancelled() { + PublishSubject ps1 = PublishSubject.create(); + PublishSubject ps2 = PublishSubject.create(); + + ps1 + .flatMap(v -> ps2) + .test(); + + ps1.onNext(1); + assertTrue("No subscribers?", ps2.hasObservers()); + + ps1.onError(new TestException()); + + assertFalse("Has subscribers?", ps2.hasObservers()); + } + + @Test + public void innerErrorsMainCancelled() { + PublishSubject ps1 = PublishSubject.create(); + PublishSubject ps2 = PublishSubject.create(); + + ps1 + .flatMap(v -> ps2) + .test(); + + ps1.onNext(1); + assertTrue("No subscribers?", ps2.hasObservers()); + + ps2.onError(new TestException()); + + assertFalse("Has subscribers?", ps1.hasObservers()); + } + + @Test + public void signalsAfterMapperCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + new Observable() { + @Override + protected void subscribeActual(@NonNull Observer observer) { + observer.onSubscribe(Disposable.empty()); + observer.onNext(1); + observer.onNext(2); + observer.onComplete(); + observer.onError(new IOException()); + } + } + .flatMap(v -> { + throw new TestException(); + }) + .test() + .assertFailure(TestException.class); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + }); + } + + @Test + public void scalarQueueTerminate() { + PublishSubject ps = PublishSubject.create(); + TestObserver to = new TestObserver<>(); + + ps + .flatMap(v -> Observable.just(v)) + .doOnNext(v -> { + if (v == 1) { + ps.onNext(2); + ps.onNext(3); + } + }) + .take(2) + .subscribe(to); + + ps.onNext(1); + + to.assertResult(1, 2); + } + + @Test + public void scalarQueueCompleteMain() throws Exception { + PublishSubject ps = PublishSubject.create(); + TestObserver to = new TestObserver<>(); + CountDownLatch cdl = new CountDownLatch(1); + ps + .flatMap(v -> Observable.just(v)) + .doOnNext(v -> { + if (v == 1) { + ps.onNext(2); + TestHelper.raceOther(() -> ps.onComplete(), cdl); + } + }) + .subscribe(to); + + ps.onNext(1); + + cdl.await(); + to.assertResult(1, 2); + } + + @Test + public void fusedInnerCrash() { + UnicastSubject us = UnicastSubject.create(); + PublishSubject ps = PublishSubject.create(); + + TestObserver to = Observable.just( + ps, + us.map(v -> { + if (v == 10) { + throw new TestException(); + } + return v; + }) + .compose(TestHelper.observableStripBoundary()) + ) + .flatMap(v -> v, true) + .doOnNext(v -> { + if (v == 1) { + ps.onNext(2); + us.onNext(10); + } + }) + .test(); + + ps.onNext(1); + ps.onComplete(); + + to.assertFailure(TestException.class, 1, 2); + } + + @Test + public void fusedInnerCrash2() { + UnicastSubject us = UnicastSubject.create(); + PublishSubject ps = PublishSubject.create(); + + TestObserver to = Observable.just( + us.map(v -> { + if (v == 10) { + throw new TestException(); + } + return v; + }) + .compose(TestHelper.observableStripBoundary()) + , ps + ) + .flatMap(v -> v, true) + .doOnNext(v -> { + if (v == 1) { + ps.onNext(2); + us.onNext(10); + } + }) + .test(); + + ps.onNext(1); + ps.onComplete(); + + to.assertFailure(TestException.class, 1, 2); + } + + @Test(timeout = 5000) + public void mixedScalarAsync() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + Observable + .range(0, 20) + .flatMap( + integer -> { + if (integer % 5 != 0) { + return Observable + .just(integer); + } + + return Observable + .just(-integer) + .observeOn(Schedulers.computation()); + }, + false, + 1 + ) + .ignoreElements() + .blockingAwait(); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlattenIterableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlattenIterableTest.java index 2fdf6b24f3c..15d6aae37bd 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlattenIterableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFlattenIterableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -96,4 +96,9 @@ public void remove() { assertEquals(1, counter.get()); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeObservable(o -> o.flatMapIterable(v -> Collections.singletonList(v))); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableForEachTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableForEachTest.java index 677b78414fd..ac8312a8935 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableForEachTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableForEachTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromActionTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromActionTest.java new file mode 100644 index 00000000000..eb201665074 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromActionTest.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.observable; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.testsupport.*; + +public class ObservableFromActionTest extends RxJavaTest { + @Test + public void fromAction() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Observable.fromAction(new Action() { + @Override + public void run() throws Exception { + atomicInteger.incrementAndGet(); + } + }) + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + } + + @Test + public void fromActionTwice() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Action run = new Action() { + @Override + public void run() throws Exception { + atomicInteger.incrementAndGet(); + } + }; + + Observable.fromAction(run) + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + + Observable.fromAction(run) + .test() + .assertResult(); + + assertEquals(2, atomicInteger.get()); + } + + @Test + public void fromActionInvokesLazy() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Observable source = Observable.fromAction(new Action() { + @Override + public void run() throws Exception { + atomicInteger.incrementAndGet(); + } + }); + + assertEquals(0, atomicInteger.get()); + + source + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + } + + @Test + public void fromActionThrows() { + Observable.fromAction(new Action() { + @Override + public void run() throws Exception { + throw new UnsupportedOperationException(); + } + }) + .test() + .assertFailure(UnsupportedOperationException.class); + } + + @SuppressWarnings("unchecked") + @Test + public void callable() throws Throwable { + final int[] counter = { 0 }; + + Observable m = Observable.fromAction(new Action() { + @Override + public void run() throws Exception { + counter[0]++; + } + }); + + assertTrue(m.getClass().toString(), m instanceof Supplier); + + assertNull(((Supplier)m).get()); + + assertEquals(1, counter[0]); + } + + @Test + public void noErrorLoss() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + final CountDownLatch cdl1 = new CountDownLatch(1); + final CountDownLatch cdl2 = new CountDownLatch(1); + + TestObserver to = Observable.fromAction(new Action() { + @Override + public void run() throws Exception { + cdl1.countDown(); + cdl2.await(5, TimeUnit.SECONDS); + } + }).subscribeOn(Schedulers.single()).test(); + + assertTrue(cdl1.await(5, TimeUnit.SECONDS)); + + to.dispose(); + + int timeout = 10; + + while (timeout-- > 0 && errors.isEmpty()) { + Thread.sleep(100); + } + + TestHelper.assertUndeliverable(errors, 0, InterruptedException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void disposedUpfront() throws Throwable { + Action run = mock(Action.class); + + Observable.fromAction(run) + .test(true) + .assertEmpty(); + + verify(run, never()).run(); + } + + @Test + public void cancelWhileRunning() { + final TestObserver to = new TestObserver<>(); + + Observable.fromAction(new Action() { + @Override + public void run() throws Exception { + to.dispose(); + } + }) + .subscribeWith(to) + .assertEmpty(); + + assertTrue(to.isDisposed()); + } + + @Test + public void asyncFused() throws Throwable { + TestObserverEx to = new TestObserverEx<>(); + to.setInitialFusionMode(QueueFuseable.ASYNC); + + Action action = mock(Action.class); + + Observable.fromAction(action) + .subscribe(to); + + to.assertFusionMode(QueueFuseable.ASYNC) + .assertResult(); + + verify(action).run(); + } + + @Test + public void syncFusedRejected() throws Throwable { + TestObserverEx to = new TestObserverEx<>(); + to.setInitialFusionMode(QueueFuseable.SYNC); + + Action action = mock(Action.class); + + Observable.fromAction(action) + .subscribe(to); + + to.assertFusionMode(QueueFuseable.NONE) + .assertResult(); + + verify(action).run(); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCallableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCallableTest.java index 43b1d96fefa..c701f60c476 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCallableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCallableTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.operators.observable; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCompletableTest.java new file mode 100644 index 00000000000..6cfd2eb0ada --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromCompletableTest.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.observable; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.fuseable.*; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.testsupport.*; + +public class ObservableFromCompletableTest extends RxJavaTest { + @Test + public void fromCompletable() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Observable.fromCompletable(Completable.fromAction(new Action() { + @Override + public void run() throws Exception { + atomicInteger.incrementAndGet(); + } + })) + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + } + + @Test + public void fromCompletableTwice() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Action run = new Action() { + @Override + public void run() throws Exception { + atomicInteger.incrementAndGet(); + } + }; + + Observable.fromCompletable(Completable.fromAction(run)) + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + + Observable.fromCompletable(Completable.fromAction(run)) + .test() + .assertResult(); + + assertEquals(2, atomicInteger.get()); + } + + @Test + public void fromCompletableInvokesLazy() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Observable source = Observable.fromCompletable(Completable.fromAction(new Action() { + @Override + public void run() throws Exception { + atomicInteger.incrementAndGet(); + } + })); + + assertEquals(0, atomicInteger.get()); + + source + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + } + + @Test + public void fromCompletableThrows() { + Observable.fromCompletable(Completable.fromAction(new Action() { + @Override + public void run() throws Exception { + throw new UnsupportedOperationException(); + } + })) + .test() + .assertFailure(UnsupportedOperationException.class); + } + + @Test + public void noErrorLoss() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + final CountDownLatch cdl1 = new CountDownLatch(1); + final CountDownLatch cdl2 = new CountDownLatch(1); + + TestObserver to = Observable.fromCompletable(Completable.fromAction(new Action() { + @Override + public void run() throws Exception { + cdl1.countDown(); + cdl2.await(5, TimeUnit.SECONDS); + } + })).subscribeOn(Schedulers.single()).test(); + + assertTrue(cdl1.await(5, TimeUnit.SECONDS)); + + to.dispose(); + + int timeout = 10; + + while (timeout-- > 0 && errors.isEmpty()) { + Thread.sleep(100); + } + + TestHelper.assertUndeliverable(errors, 0, InterruptedException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void disposedUpfront() throws Throwable { + Action run = mock(Action.class); + + Observable.fromCompletable(Completable.fromAction(run)) + .test(true) + .assertEmpty(); + + verify(run, never()).run(); + } + + @Test + public void cancelWhileRunning() { + final TestObserver to = new TestObserver<>(); + + Observable.fromCompletable(Completable.fromAction(new Action() { + @Override + public void run() throws Exception { + to.dispose(); + } + })) + .subscribeWith(to) + .assertEmpty(); + + assertTrue(to.isDisposed()); + } + + @Test + public void asyncFused() throws Throwable { + TestObserverEx to = new TestObserverEx<>(); + to.setInitialFusionMode(QueueFuseable.ASYNC); + + Action action = mock(Action.class); + + Observable.fromCompletable(Completable.fromAction(action)) + .subscribe(to); + + to.assertFusionMode(QueueFuseable.ASYNC) + .assertResult(); + + verify(action).run(); + } + + @Test + public void syncFusedRejected() throws Throwable { + TestObserverEx to = new TestObserverEx<>(); + to.setInitialFusionMode(QueueFuseable.SYNC); + + Action action = mock(Action.class); + + Observable.fromCompletable(Completable.fromAction(action)) + .subscribe(to); + + to.assertFusionMode(QueueFuseable.NONE) + .assertResult(); + + verify(action).run(); + } + + @Test + public void disposed() { + TestHelper.checkDisposed(Observable.fromCompletable(Completable.never())); + } + + @Test + public void upstream() { + Observable o = Observable.fromCompletable(Completable.never()); + assertTrue(o instanceof HasUpstreamCompletableSource); + assertSame(Completable.never(), ((HasUpstreamCompletableSource)o).source()); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromIterableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromIterableTest.java index d744472b660..b816baf4b08 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromIterableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromIterableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -29,18 +29,14 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.util.CrashingIterable; import io.reactivex.rxjava3.observers.*; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.testsupport.*; public class ObservableFromIterableTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void nullValue() { - Observable.fromIterable(null); - } - @Test public void listIterable() { Observable o = Observable.fromIterable(Arrays. asList("one", "two", "three")); @@ -350,4 +346,28 @@ public void onComplete() { } }); } + + @Test + public void disposeAfterHasNext() { + TestObserver to = new TestObserver<>(); + + Observable.fromIterable(() -> new Iterator() { + int count; + @Override + public boolean hasNext() { + if (count++ == 2) { + to.dispose(); + return false; + } + return true; + } + + @Override + public Integer next() { + return 1; + } + }) + .subscribeWith(to) + .assertValuesOnly(1, 1); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromMaybeTest.java new file mode 100644 index 00000000000..e0175b4a595 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromMaybeTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.observable; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.subjects.MaybeSubject; +import io.reactivex.rxjava3.testsupport.TestObserverEx; + +public class ObservableFromMaybeTest extends RxJavaTest { + + @Test + public void success() { + Observable.fromMaybe(Maybe.just(1).hide()) + .test() + .assertResult(1); + } + + @Test + public void empty() { + Observable.fromMaybe(Maybe.empty().hide()) + .test() + .assertResult(); + } + + @Test + public void error() { + Observable.fromMaybe(Maybe.error(new TestException()).hide()) + .test() + .assertFailure(TestException.class); + } + + @Test + public void cancelComposes() { + MaybeSubject ms = MaybeSubject.create(); + + TestObserver to = Observable.fromMaybe(ms) + .test(); + + to.assertEmpty(); + + assertTrue(ms.hasObservers()); + + to.dispose(); + + assertFalse(ms.hasObservers()); + } + + @Test + public void asyncFusion() { + TestObserverEx to = new TestObserverEx<>(); + to.setInitialFusionMode(QueueFuseable.ASYNC); + + Observable.fromMaybe(Maybe.just(1)) + .subscribe(to); + + to + .assertFuseable() + .assertFusionMode(QueueFuseable.ASYNC) + .assertResult(1); + } + + @Test + public void syncFusionRejected() { + TestObserverEx to = new TestObserverEx<>(); + to.setInitialFusionMode(QueueFuseable.SYNC); + + Observable.fromMaybe(Maybe.just(1)) + .subscribe(to); + + to + .assertFuseable() + .assertFusionMode(QueueFuseable.NONE) + .assertResult(1); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromRunnableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromRunnableTest.java new file mode 100644 index 00000000000..b566f66775f --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromRunnableTest.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.observable; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.Supplier; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.testsupport.*; + +public class ObservableFromRunnableTest extends RxJavaTest { + @Test + public void fromRunnable() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Observable.fromRunnable(new Runnable() { + @Override + public void run() { + atomicInteger.incrementAndGet(); + } + }) + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + } + + @Test + public void fromRunnableTwice() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Runnable run = new Runnable() { + @Override + public void run() { + atomicInteger.incrementAndGet(); + } + }; + + Observable.fromRunnable(run) + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + + Observable.fromRunnable(run) + .test() + .assertResult(); + + assertEquals(2, atomicInteger.get()); + } + + @Test + public void fromRunnableInvokesLazy() { + final AtomicInteger atomicInteger = new AtomicInteger(); + + Observable source = Observable.fromRunnable(new Runnable() { + @Override + public void run() { + atomicInteger.incrementAndGet(); + } + }); + + assertEquals(0, atomicInteger.get()); + + source + .test() + .assertResult(); + + assertEquals(1, atomicInteger.get()); + } + + @Test + public void fromRunnableThrows() { + Observable.fromRunnable(new Runnable() { + @Override + public void run() { + throw new UnsupportedOperationException(); + } + }) + .test() + .assertFailure(UnsupportedOperationException.class); + } + + @SuppressWarnings("unchecked") + @Test + public void callable() throws Throwable { + final int[] counter = { 0 }; + + Observable m = Observable.fromRunnable(new Runnable() { + @Override + public void run() { + counter[0]++; + } + }); + + assertTrue(m.getClass().toString(), m instanceof Supplier); + + assertNull(((Supplier)m).get()); + + assertEquals(1, counter[0]); + } + + @Test + public void noErrorLoss() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + final CountDownLatch cdl1 = new CountDownLatch(1); + final CountDownLatch cdl2 = new CountDownLatch(1); + + TestObserver to = Observable.fromRunnable(new Runnable() { + @Override + public void run() { + cdl1.countDown(); + try { + cdl2.await(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + throw new TestException(e); + } + } + }).subscribeOn(Schedulers.single()).test(); + + assertTrue(cdl1.await(5, TimeUnit.SECONDS)); + + to.dispose(); + + int timeout = 10; + + while (timeout-- > 0 && errors.isEmpty()) { + Thread.sleep(100); + } + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void disposedUpfront() throws Throwable { + Runnable run = mock(Runnable.class); + + Observable.fromRunnable(run) + .test(true) + .assertEmpty(); + + verify(run, never()).run(); + } + + @Test + public void cancelWhileRunning() { + final TestObserver to = new TestObserver<>(); + + Observable.fromRunnable(new Runnable() { + @Override + public void run() { + to.dispose(); + } + }) + .subscribeWith(to) + .assertEmpty(); + + assertTrue(to.isDisposed()); + } + + @Test + public void asyncFused() throws Throwable { + TestObserverEx to = new TestObserverEx<>(); + to.setInitialFusionMode(QueueFuseable.ASYNC); + + Runnable action = mock(Runnable.class); + + Observable.fromRunnable(action) + .subscribe(to); + + to.assertFusionMode(QueueFuseable.ASYNC) + .assertResult(); + + verify(action).run(); + } + + @Test + public void syncFusedRejected() throws Throwable { + TestObserverEx to = new TestObserverEx<>(); + to.setInitialFusionMode(QueueFuseable.SYNC); + + Runnable action = mock(Runnable.class); + + Observable.fromRunnable(action) + .subscribe(to); + + to.assertFusionMode(QueueFuseable.NONE) + .assertResult(); + + verify(action).run(); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromSingleTest.java new file mode 100644 index 00000000000..aaabb513b34 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromSingleTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.observable; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.subjects.SingleSubject; +import io.reactivex.rxjava3.testsupport.TestObserverEx; + +public class ObservableFromSingleTest extends RxJavaTest { + + @Test + public void success() { + Observable.fromSingle(Single.just(1).hide()) + .test() + .assertResult(1); + } + + @Test + public void error() { + Observable.fromSingle(Single.error(new TestException()).hide()) + .test() + .assertFailure(TestException.class); + } + + @Test + public void cancelComposes() { + SingleSubject ms = SingleSubject.create(); + + TestObserver to = Observable.fromSingle(ms) + .test(); + + to.assertEmpty(); + + assertTrue(ms.hasObservers()); + + to.dispose(); + + assertFalse(ms.hasObservers()); + } + + @Test + public void asyncFusion() { + TestObserverEx to = new TestObserverEx<>(); + to.setInitialFusionMode(QueueFuseable.ASYNC); + + Observable.fromSingle(Single.just(1)) + .subscribe(to); + + to + .assertFuseable() + .assertFusionMode(QueueFuseable.ASYNC) + .assertResult(1); + } + + @Test + public void syncFusionRejected() { + TestObserverEx to = new TestObserverEx<>(); + to.setInitialFusionMode(QueueFuseable.SYNC); + + Observable.fromSingle(Single.just(1)) + .subscribe(to); + + to + .assertFuseable() + .assertFusionMode(QueueFuseable.NONE) + .assertResult(1); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromSupplierTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromSupplierTest.java index 2b181a56fe9..56e31ddfb78 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromSupplierTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromSupplierTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.operators.observable; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromTest.java index 0bc7a099977..639d3c4d14d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableFromTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,7 +21,8 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.ScalarSupplier; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.testsupport.*; @@ -30,7 +31,8 @@ public class ObservableFromTest extends RxJavaTest { @Test public void fromFutureTimeout() throws Exception { Observable.fromFuture(Observable.never() - .toFuture(), 100, TimeUnit.MILLISECONDS, Schedulers.io()) + .toFuture(), 100, TimeUnit.MILLISECONDS) + .subscribeOn(Schedulers.io()) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(TimeoutException.class); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGenerateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGenerateTest.java index 19735a3ad4b..90a3d60eaf1 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGenerateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGenerateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -194,4 +194,17 @@ public void accept(Emitter e) throws Exception { .test() .assertResult(); } + + @Test + public void onNextAfterOnComplete() { + Observable.generate(new Consumer>() { + @Override + public void accept(Emitter e) throws Exception { + e.onComplete(); + e.onNext(1); + } + }) + .test() + .assertResult(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupByTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupByTest.java index 28d3f2d6432..32c1abc2e2f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupByTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupByTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,14 +27,14 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.observables.GroupedObservable; import io.reactivex.rxjava3.observers.*; import io.reactivex.rxjava3.schedulers.Schedulers; -import io.reactivex.rxjava3.subjects.PublishSubject; +import io.reactivex.rxjava3.subjects.*; import io.reactivex.rxjava3.testsupport.*; public class ObservableGroupByTest extends RxJavaTest { @@ -96,6 +96,7 @@ public void empty() { } @Test + @SuppressUndeliverable public void error() { Observable sourceStrings = Observable.just("one", "two", "three", "four", "five", "six"); Observable errorSource = Observable.error(new RuntimeException("forced failure")); @@ -1178,6 +1179,7 @@ public void keySelectorThrows() { } @Test + @SuppressUndeliverable public void valueSelectorThrows() { Observable source = Observable.just(0, 1, 2, 3, 4, 5, 6); @@ -1233,6 +1235,7 @@ public void accept(GroupedObservable t1) { } @Test + @SuppressUndeliverable public void error2() { Observable source = Observable.concat(Observable.just(0), Observable. error(new TestException("Forced failure"))); @@ -1446,6 +1449,7 @@ public Integer apply(Integer i) { } @Test + @SuppressUndeliverable public void keySelectorAndDelayError() { Observable.just(1).concatWith(Observable.error(new TestException())) .groupBy(Functions.identity(), true) @@ -1460,6 +1464,7 @@ public ObservableSource apply(GroupedObservable g) th } @Test + @SuppressUndeliverable public void keyAndValueSelectorAndDelayError() { Observable.just(1).concatWith(Observable.error(new TestException())) .groupBy(Functions.identity(), Functions.identity(), true) @@ -1672,4 +1677,68 @@ public void accept(GroupedObservable g) throws Throwable { to2.assertFailure(TestException.class, 1); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeObservable(o -> o.groupBy(v -> v)); + } + + @Test + public void nullKeyDisposeGroup() { + Observable.just(1) + .groupBy(v -> null) + .flatMap(v -> v.take(1)) + .test() + .assertResult(1); + } + + @Test + public void groupSubscribeOnNextRace() throws Throwable { + for (int i = 0; i < TestHelper.RACE_LONG_LOOPS; i++) { + BehaviorSubject bs = BehaviorSubject.createDefault(1); + CountDownLatch cdl = new CountDownLatch(1); + + bs.groupBy(v -> 1) + .doOnNext(g -> { + TestHelper.raceOther(() -> { + g.test(); + }, cdl); + }) + .test(); + + cdl.await(); + } + } + + @Test + public void abandonedGroupDispose() { + AtomicReference> ref = new AtomicReference<>(); + + Observable.just(1) + .groupBy(v -> 1) + .doOnNext(ref::set) + .test(); + + ref.get().take(1).test().assertResult(1); + } + + @Test + public void delayErrorCompleteMoreWorkInGroup() { + PublishSubject ps = PublishSubject.create(); + + TestObserver to = ps.groupBy(v -> 1, true) + .flatMap(g -> g.doOnNext(v -> { + if (v == 1) { + ps.onNext(2); + ps.onComplete(); + } + }) + ) + .test() + ; + + ps.onNext(1); + + to.assertResult(1, 2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupJoinTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupJoinTest.java index 5998e37a646..7959f90a055 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupJoinTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableGroupJoinTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import static org.junit.Assert.*; @@ -81,7 +79,7 @@ public Integer apply(Integer rightValue) throws Throwable { @Before public void before() { - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this); } @Test @@ -479,6 +477,7 @@ public Observable apply(Integer r, Observable l) throws Except } @Test + @SuppressUndeliverable public void innerErrorRight() { Observable.just(1) .groupJoin( @@ -726,4 +725,42 @@ public void leftRightEndState() { verify(js).innerClose(false, o); } + + @Test + public void disposeAfterOnNext() { + PublishSubject ps1 = PublishSubject.create(); + PublishSubject ps2 = PublishSubject.create(); + + TestObserver to = new TestObserver<>(); + + ps1.groupJoin(ps2, v -> Observable.never(), v -> Observable.never(), (a, b) -> a) + .doOnNext(v -> { + to.dispose(); + }) + .subscribe(to); + + ps2.onNext(1); + ps1.onNext(1); + } + + @Test + public void completeWithMoreWork() { + PublishSubject ps1 = PublishSubject.create(); + PublishSubject ps2 = PublishSubject.create(); + + TestObserver to = new TestObserver<>(); + + ps1.groupJoin(ps2, v -> Observable.never(), v -> Observable.never(), (a, b) -> a) + .doOnNext(v -> { + if (v == 1) { + ps2.onNext(2); + ps1.onComplete(); + ps2.onComplete(); + } + }) + .subscribe(to); + + ps2.onNext(1); + ps1.onNext(1); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableHideTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableHideTest.java index 45361b1aedb..0b624621ec8 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableHideTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableHideTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIgnoreElementsTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIgnoreElementsTest.java index 43af8631e9e..c7597c3a9f7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIgnoreElementsTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIgnoreElementsTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableInternalHelperTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableInternalHelperTest.java index 9c02f95ebb7..87fc866f74e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableInternalHelperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableInternalHelperTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import static org.junit.Assert.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIntervalRangeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIntervalRangeTest.java index 95f26637bf5..637d9164be9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIntervalRangeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIntervalRangeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -85,4 +85,12 @@ public void cancel() { .test() .assertResult(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L); } + + @Test + public void takeSameAsRange() { + Observable.intervalRange(0, 2, 1, 1, TimeUnit.MILLISECONDS, Schedulers.trampoline()) + .take(2) + .test() + .assertResult(0L, 1L); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIntervalTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIntervalTest.java index 4f188093c54..e8126962deb 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIntervalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableIntervalTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableJoinTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableJoinTest.java index aa173610264..c6f439cdcb4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableJoinTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableJoinTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.observable; import static org.mockito.ArgumentMatchers.any; @@ -54,7 +52,7 @@ public Observable apply(Integer t1) { @Before public void before() { - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this); } @Test @@ -446,4 +444,27 @@ public Integer apply(Integer a, Integer b) throws Exception { RxJavaPlugins.reset(); } } + + @Test + public void bothTerminateWithWorkRemaining() { + PublishSubject ps1 = PublishSubject.create(); + PublishSubject ps2 = PublishSubject.create(); + + TestObserver to = ps1.join( + ps2, + v -> Observable.never(), + v -> Observable.never(), + (a, b) -> a + b) + .doOnNext(v -> { + ps1.onComplete(); + ps2.onNext(2); + ps2.onComplete(); + }) + .test(); + + ps1.onNext(0); + ps2.onNext(1); + + to.assertComplete(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLastTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLastTest.java index 0bd5868332b..cabed665f41 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLastTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLastTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLiftTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLiftTest.java index 325fc504ae9..b761a6ad021 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLiftTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableLiftTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,10 +19,12 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.testsupport.SuppressUndeliverable; public class ObservableLiftTest extends RxJavaTest { @Test + @SuppressUndeliverable public void callbackCrash() { try { Observable.just(1) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMapNotificationTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMapNotificationTest.java index 81b470ff99e..0672f528c98 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMapNotificationTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMapNotificationTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMapTest.java index 538feaaa7fd..4919a74f0db 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,7 @@ import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subjects.UnicastSubject; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMaterializeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMaterializeTest.java index 0e1df287bce..02b16ad6cea 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMaterializeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMaterializeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeDelayErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeDelayErrorTest.java index fefce528674..da92bc03380 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeDelayErrorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeDelayErrorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeMaxConcurrentTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeMaxConcurrentTest.java index 9ab92edc123..e1388f39ad4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeMaxConcurrentTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeMaxConcurrentTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeTest.java index d5b9a45a6f8..02ddf09fd0b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithCompletableTest.java index e561eaac1eb..4b9ee5a9d2d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithMaybeTest.java index 43f0a7fff79..3140c5c118e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithMaybeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithMaybeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithSingleTest.java index c6b083f41d2..9d6171ba06f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableMergeWithSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableObserveOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableObserveOnTest.java index 2b8c2e02741..5f41470db05 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableObserveOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableObserveOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -31,11 +31,13 @@ import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.operators.flowable.FlowableObserveOnTest.DisposeTrackingScheduler; import io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn.ObserveOnObserver; import io.reactivex.rxjava3.internal.schedulers.ImmediateThinScheduler; import io.reactivex.rxjava3.observers.*; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.SimpleQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.*; import io.reactivex.rxjava3.subjects.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorCompleteTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorCompleteTest.java new file mode 100644 index 00000000000..a4671dd5351 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorCompleteTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.observable; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.subjects.PublishSubject; +import io.reactivex.rxjava3.testsupport.*; + +public class ObservableOnErrorCompleteTest { + + @Test + public void normal() { + Observable.range(1, 10) + .onErrorComplete() + .test() + .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + + @Test + public void empty() { + Observable.empty() + .onErrorComplete() + .test() + .assertResult(); + } + + @Test + public void error() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Observable.error(new TestException()) + .onErrorComplete() + .test() + .assertResult(); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void errorMatches() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Observable.error(new TestException()) + .onErrorComplete(error -> error instanceof TestException) + .test() + .assertResult(); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void errorNotMatches() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Observable.error(new IOException()) + .onErrorComplete(error -> error instanceof TestException) + .test() + .assertFailure(IOException.class); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void errorPredicateCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + TestObserverEx to = Observable.error(new IOException()) + .onErrorComplete(error -> { throw new TestException(); }) + .subscribeWith(new TestObserverEx<>()) + .assertFailure(CompositeException.class); + + TestHelper.assertError(to, 0, IOException.class); + TestHelper.assertError(to, 1, TestException.class); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void itemsThenError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Observable.range(1, 5) + .map(v -> 4 / (3 - v)) + .onErrorComplete() + .test() + .assertResult(2, 4); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void dispose() { + PublishSubject ps = PublishSubject.create(); + + TestObserver to = ps + .onErrorComplete() + .test(); + + assertTrue("No subscribers?!", ps.hasObservers()); + + to.dispose(); + + assertFalse("Still subscribers?!", ps.hasObservers()); + } + + @Test + public void onSubscribe() { + TestHelper.checkDoubleOnSubscribeObservable(f -> f.onErrorComplete()); + } + + @Test + public void isDisposed() { + TestHelper.checkDisposed(PublishSubject.create().onErrorComplete()); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorResumeNextTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorResumeNextTest.java index 386b6c96a19..ed3e8dc5710 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorResumeNextTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorResumeNextTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorResumeWithTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorResumeWithTest.java index f60ea43a256..7b659c94447 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorResumeWithTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorResumeWithTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorReturnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorReturnTest.java index 69c6c6889cc..da7acf2b478 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorReturnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableOnErrorReturnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservablePublishTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservablePublishTest.java index 16cb03d00e7..edec6a517dd 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservablePublishTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservablePublishTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -866,4 +866,31 @@ public void disposeResets() { to.assertValuesOnly(1); } + + @Test + public void disposeNoNeedForReset() { + PublishSubject ps = PublishSubject.create(); + + ConnectableObservable co = ps.publish(); + + TestObserver to = co.test(); + + Disposable d = co.connect(); + + ps.onNext(1); + + d.dispose(); + + to = co.test(); + + to.assertEmpty(); + + co.connect(); + + to.assertEmpty(); + + ps.onNext(2); + + to.assertValuesOnly(2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRangeLongTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRangeLongTest.java index 7a58572d2f0..c19219cdea1 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRangeLongTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRangeLongTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,8 +24,8 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.functions.Consumer; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.observers.*; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.testsupport.*; public class ObservableRangeLongTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRangeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRangeTest.java index e789b55093c..0f461a71546 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRangeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRangeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,8 +24,8 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.functions.Consumer; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.observers.*; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.testsupport.*; public class ObservableRangeTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRedoTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRedoTest.java index 2dc15f230e0..adb2caf4a38 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRedoTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRedoTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceTest.java index d997e9899f1..0feab233d3f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReduceTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRefCountTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRefCountTest.java index d9b98de8f9a..638f694a880 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRefCountTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRefCountTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -45,7 +45,25 @@ public class ObservableRefCountTest extends RxJavaTest { @Test - public void refCountAsync() { + public void refCountAsync() throws InterruptedException { + // Flaky + for (int i = 0; i < 10; i++) { + try { + refCountAsyncActual(); + return; + } catch (AssertionError ex) { + if (i == 9) { + throw ex; + } + Thread.sleep((int)(200 * (Math.random() * 10 + 1))); + } + } + } + + /** + * Tries to coordinate async counting but it is flaky due to the low 10s of milliseconds. + */ + void refCountAsyncActual() { final AtomicInteger subscribeCount = new AtomicInteger(); final AtomicInteger nextCount = new AtomicInteger(); Observable r = Observable.interval(0, 25, TimeUnit.MILLISECONDS) @@ -837,6 +855,7 @@ protected void subscribeActual(Observer observer) { } @Test + @SuppressUndeliverable public void badSourceSubscribe() { BadObservableSubscribe bo = new BadObservableSubscribe(); @@ -863,6 +882,7 @@ public void badSourceDispose() { } @Test + @SuppressUndeliverable public void badSourceConnect() { BadObservableConnect bo = new BadObservableConnect(); @@ -904,6 +924,7 @@ protected void subscribeActual(Observer observer) { } @Test + @SuppressUndeliverable public void badSourceSubscribe2() { BadObservableSubscribe2 bo = new BadObservableSubscribe2(); @@ -941,6 +962,7 @@ protected void subscribeActual(Observer observer) { } @Test + @SuppressUndeliverable public void badSourceCompleteDisconnect() { BadObservableConnect2 bo = new BadObservableConnect2(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeatTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeatTest.java index 78c793f1b45..8f3287e7e02 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeatTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRepeatTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReplayEagerTruncateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReplayEagerTruncateTest.java index fe2c59d088b..aa1bcb43592 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReplayEagerTruncateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReplayEagerTruncateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,7 +30,7 @@ import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.core.Scheduler.Worker; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; @@ -1976,4 +1976,85 @@ public void timeAndSizeNoTerminalTruncationOnTimechange() { .assertComplete() .assertNoErrors(); } + + @Test + public void disposeNoNeedForResetSizeBound() { + PublishSubject ps = PublishSubject.create(); + + ConnectableObservable co = ps.replay(10, true); + + TestObserver to = co.test(); + + Disposable d = co.connect(); + + ps.onNext(1); + + d.dispose(); + + to = co.test(); + + to.assertEmpty(); + + co.connect(); + + to.assertEmpty(); + + ps.onNext(2); + + to.assertValuesOnly(2); + } + + @Test + public void disposeNoNeedForResetTimeBound() { + PublishSubject ps = PublishSubject.create(); + + ConnectableObservable co = ps.replay(10, TimeUnit.MINUTES, Schedulers.single(), true); + + TestObserver to = co.test(); + + Disposable d = co.connect(); + + ps.onNext(1); + + d.dispose(); + + to = co.test(); + + to.assertEmpty(); + + co.connect(); + + to.assertEmpty(); + + ps.onNext(2); + + to.assertValuesOnly(2); + } + + @Test + public void disposeNoNeedForResetTimeAndSIzeBound() { + PublishSubject ps = PublishSubject.create(); + + ConnectableObservable co = ps.replay(10, 10, TimeUnit.MINUTES, Schedulers.single(), true); + + TestObserver to = co.test(); + + Disposable d = co.connect(); + + ps.onNext(1); + + d.dispose(); + + to = co.test(); + + to.assertEmpty(); + + co.connect(); + + to.assertEmpty(); + + ps.onNext(2); + + to.assertValuesOnly(2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReplayTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReplayTest.java index 9b31f51e8d3..8b4ef97d029 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReplayTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableReplayTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -1698,4 +1698,57 @@ public void accept(byte[] v) throws Exception { Assert.fail("Bounded Replay Leak check: Memory leak detected: " + (initial / 1024.0 / 1024.0) + " -> " + after.get() / 1024.0 / 1024.0); } - }} + } + + @Test(expected = TestException.class) + public void connectDisposeCrash() { + ConnectableObservable co = Observable.never().replay(); + + co.connect(); + + co.connect(d -> { throw new TestException(); }); + } + + @Test + public void resetWhileNotConnectedIsNoOp() { + ConnectableObservable co = Observable.never().replay(); + + co.reset(); + } + + @Test + public void resetWhileActiveIsNoOp() { + ConnectableObservable co = Observable.never().replay(); + + co.connect(); + + co.reset(); + } + + @Test + public void disposeNoNeedForReset() { + PublishSubject ps = PublishSubject.create(); + + ConnectableObservable co = ps.replay(); + + TestObserver to = co.test(); + + Disposable d = co.connect(); + + ps.onNext(1); + + d.dispose(); + + to = co.test(); + + to.assertEmpty(); + + co.connect(); + + to.assertEmpty(); + + ps.onNext(2); + + to.assertValuesOnly(2); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableResourceWrapperTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableResourceWrapperTest.java index 228725c0a0c..42d557e091f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableResourceWrapperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableResourceWrapperTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryTest.java index 94009c5b86a..13f19fb547c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -572,7 +572,7 @@ public void run() { } } - /** Observer for listener on seperate thread. */ + /** Observer for listener on separate thread. */ static final class AsyncObserver extends DefaultObserver { protected CountDownLatch latch = new CountDownLatch(1); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryWithPredicateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryWithPredicateTest.java index 3b57f6c2e12..bce6e9f6599 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryWithPredicateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableRetryWithPredicateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -37,6 +37,7 @@ import io.reactivex.rxjava3.testsupport.*; public class ObservableRetryWithPredicateTest extends RxJavaTest { + BiPredicate retryTwice = new BiPredicate() { @Override public boolean test(Integer t1, Throwable t2) { @@ -390,6 +391,7 @@ public void dontRetry() { } @Test + @SuppressUndeliverable public void retryDisposeRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { final PublishSubject ps = PublishSubject.create(); @@ -438,6 +440,7 @@ public boolean test(Integer n, Throwable e) throws Exception { } @Test + @SuppressUndeliverable public void retryBiPredicateDisposeRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { final PublishSubject ps = PublishSubject.create(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSampleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSampleTest.java index 0861fc2596f..7da1bfcbda3 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSampleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSampleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -439,4 +439,8 @@ public Observable apply(Observable o) }); } + @Test + public void doubleOnSubscribeObservable() { + TestHelper.checkDoubleOnSubscribeObservable(o -> o.sample(Observable.never())); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScalarXMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScalarXMapTest.java index bffd568b70c..c27b2e17c04 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScalarXMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScalarXMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,6 +23,7 @@ import io.reactivex.rxjava3.internal.disposables.EmptyDisposable; import io.reactivex.rxjava3.internal.operators.observable.ObservableScalarXMap.ScalarDisposable; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.testsupport.TestHelper; public class ObservableScalarXMapTest extends RxJavaTest { @@ -234,4 +235,13 @@ public void run() { TestHelper.race(r1, r2); } } + + @Test + public void scalarDisposbleWrongFusion() { + TestObserver to = new TestObserver<>(); + final ScalarDisposable sd = new ScalarDisposable<>(to, 1); + to.onSubscribe(sd); + + assertEquals(QueueFuseable.NONE, sd.requestFusion(QueueFuseable.ASYNC)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScanTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScanTest.java index c482d121be7..9a1765ceb3e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScanTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableScanTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSequenceEqualTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSequenceEqualTest.java index 3d805ec79a0..645fafbb625 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSequenceEqualTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSequenceEqualTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -336,4 +336,77 @@ public void run() { to.assertEmpty(); } } + + @Test + public void firstCompletesBeforeSecond() { + Observable.sequenceEqual(Observable.just(1), Observable.empty()) + .test() + .assertResult(false); + } + + @Test + public void secondCompletesBeforeFirst() { + Observable.sequenceEqual(Observable.empty(), Observable.just(1)) + .test() + .assertResult(false); + } + + @Test + public void bothEmpty() { + Observable.sequenceEqual(Observable.empty(), Observable.empty()) + .test() + .assertResult(true); + } + + @Test + public void bothJust() { + Observable.sequenceEqual(Observable.just(1), Observable.just(1)) + .test() + .assertResult(true); + } + + @Test + public void bothCompleteWhileComparing() { + PublishSubject ps1 = PublishSubject.create(); + PublishSubject ps2 = PublishSubject.create(); + + TestObserver to = Observable.sequenceEqual(ps1, ps2, (a, b) -> { + ps1.onNext(1); + ps1.onComplete(); + + ps2.onNext(1); + ps2.onComplete(); + return a.equals(b); + }) + .test() + ; + + ps1.onNext(0); + ps2.onNext(0); + + to.assertResult(true); + } + + @Test + public void bothCompleteWhileComparingAsObservable() { + PublishSubject ps1 = PublishSubject.create(); + PublishSubject ps2 = PublishSubject.create(); + + TestObserver to = Observable.sequenceEqual(ps1, ps2, (a, b) -> { + ps1.onNext(1); + ps1.onComplete(); + + ps2.onNext(1); + ps2.onComplete(); + return a.equals(b); + }) + .toObservable() + .test() + ; + + ps1.onNext(0); + ps2.onNext(0); + + to.assertResult(true); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSerializeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSerializeTest.java index 2a2b7dff0dd..9aa31211b5f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSerializeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSerializeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -78,7 +78,22 @@ public void multiThreadedBasic() { } @Test - public void multiThreadedWithNPE() { + public void multiThreadedWithNPEFlaky() throws InterruptedException { + int max = 9; + for (int i = 0; i <= max; i++) { + try { + multiThreadedWithNPE(); + return; + } catch (AssertionError ex) { + if (i == max) { + throw ex; + } + } + Thread.sleep((long)(1000 * Math.random() + 100)); + } + } + + void multiThreadedWithNPE() { TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable("one", "two", "three", null); Observable w = Observable.unsafeCreate(onSubscribe); @@ -107,7 +122,22 @@ public void multiThreadedWithNPE() { } @Test - public void multiThreadedWithNPEinMiddle() { + public void multiThreadedWithNPEinMiddleFlaky() throws InterruptedException { + int max = 9; + for (int i = 0; i <= max; i++) { + try { + multiThreadedWithNPEinMiddle(); + return; + } catch (AssertionError ex) { + if (i == max) { + throw ex; + } + } + Thread.sleep((long)(1000 * Math.random() + 100)); + } + } + + void multiThreadedWithNPEinMiddle() { boolean lessThan9 = false; for (int i = 0; i < 3; i++) { TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable("one", "two", "three", null, "four", "five", "six", "seven", "eight", "nine"); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSingleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSingleTest.java index 2290c645ca7..c511f28baf1 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLastTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLastTest.java index 8edf026fe1d..1a10af31d2f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLastTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLastTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -92,7 +92,7 @@ public void skipLastWithBackpressure() { } - @Test(expected = IndexOutOfBoundsException.class) + @Test(expected = IllegalArgumentException.class) public void skipLastWithNegativeCount() { Observable.just("one").skipLast(-1); } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLastTimedTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLastTimedTest.java index d0a1b24fa2d..a4171ea2dfa 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLastTimedTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipLastTimedTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -194,7 +194,7 @@ public ObservableSource apply(Observable o) throws Exception { } @Test - public void onNextDisposeRace() { + public void onCompleteDisposeRace() { TestScheduler scheduler = new TestScheduler(); for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { final PublishSubject ps = PublishSubject.create(); @@ -219,6 +219,32 @@ public void run() { } } + @Test + public void onCompleteDisposeDelayErrorRace() { + TestScheduler scheduler = new TestScheduler(); + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + final PublishSubject ps = PublishSubject.create(); + + final TestObserver to = ps.skipLast(1, TimeUnit.DAYS, scheduler, true).test(); + + Runnable r1 = new Runnable() { + @Override + public void run() { + ps.onComplete(); + } + }; + + Runnable r2 = new Runnable() { + @Override + public void run() { + to.dispose(); + } + }; + + TestHelper.race(r1, r2); + } + } + @Test public void errorDelayed() { Observable.error(new TestException()) @@ -236,4 +262,177 @@ public void take() { .awaitDone(5, TimeUnit.SECONDS) .assertResult(1); } + + @Test + public void onNextDisposeRace() { + TestScheduler scheduler = new TestScheduler(); + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + final PublishSubject ps = PublishSubject.create(); + + final TestObserver to = ps.skipLast(1, TimeUnit.DAYS, scheduler).test(); + + Runnable r1 = new Runnable() { + @Override + public void run() { + ps.onNext(1); + } + }; + + Runnable r2 = new Runnable() { + @Override + public void run() { + to.dispose(); + } + }; + + TestHelper.race(r1, r2); + } + } + + @Test + public void onNextOnCompleteDisposeDelayErrorRace() { + TestScheduler scheduler = new TestScheduler(); + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + final PublishSubject ps = PublishSubject.create(); + + final TestObserver to = ps.skipLast(1, TimeUnit.DAYS, scheduler, true).test(); + + Runnable r1 = new Runnable() { + @Override + public void run() { + ps.onNext(1); + ps.onComplete(); + } + }; + + Runnable r2 = new Runnable() { + @Override + public void run() { + to.dispose(); + } + }; + + TestHelper.race(r1, r2); + } + } + + @Test + public void skipLastTimedDelayError() { + TestScheduler scheduler = new TestScheduler(); + + PublishSubject source = PublishSubject.create(); + + // FIXME the timeunit now matters due to rounding + Observable result = source.skipLast(1000, TimeUnit.MILLISECONDS, scheduler, true); + + Observer o = TestHelper.mockObserver(); + + result.subscribe(o); + + source.onNext(1); + source.onNext(2); + source.onNext(3); + + scheduler.advanceTimeBy(500, TimeUnit.MILLISECONDS); + + source.onNext(4); + source.onNext(5); + source.onNext(6); + + scheduler.advanceTimeBy(950, TimeUnit.MILLISECONDS); + source.onComplete(); + + InOrder inOrder = inOrder(o); + inOrder.verify(o).onNext(1); + inOrder.verify(o).onNext(2); + inOrder.verify(o).onNext(3); + inOrder.verify(o, never()).onNext(4); + inOrder.verify(o, never()).onNext(5); + inOrder.verify(o, never()).onNext(6); + inOrder.verify(o).onComplete(); + inOrder.verifyNoMoreInteractions(); + + verify(o, never()).onError(any(Throwable.class)); + } + + @Test + public void skipLastTimedErrorBeforeTimeDelayError() { + TestScheduler scheduler = new TestScheduler(); + + PublishSubject source = PublishSubject.create(); + + Observable result = source.skipLast(1, TimeUnit.SECONDS, scheduler, true); + + Observer o = TestHelper.mockObserver(); + + result.subscribe(o); + + source.onNext(1); + source.onNext(2); + source.onNext(3); + source.onError(new TestException()); + + scheduler.advanceTimeBy(1050, TimeUnit.MILLISECONDS); + + verify(o).onError(any(TestException.class)); + + verify(o, never()).onComplete(); + verify(o, never()).onNext(any()); + } + + @Test + public void skipLastTimedCompleteBeforeTimeDelayError() { + TestScheduler scheduler = new TestScheduler(); + + PublishSubject source = PublishSubject.create(); + + Observable result = source.skipLast(1, TimeUnit.SECONDS, scheduler, true); + + Observer o = TestHelper.mockObserver(); + + result.subscribe(o); + + source.onNext(1); + source.onNext(2); + source.onNext(3); + + scheduler.advanceTimeBy(500, TimeUnit.MILLISECONDS); + + source.onComplete(); + + InOrder inOrder = inOrder(o); + inOrder.verify(o).onComplete(); + inOrder.verifyNoMoreInteractions(); + + verify(o, never()).onNext(any()); + verify(o, never()).onError(any(Throwable.class)); + } + + @Test + public void skipLastTimedWhenAllElementsAreValidDelayError() { + TestScheduler scheduler = new TestScheduler(); + + PublishSubject source = PublishSubject.create(); + + Observable result = source.skipLast(1, TimeUnit.MILLISECONDS, scheduler, true); + + Observer o = TestHelper.mockObserver(); + + result.subscribe(o); + + source.onNext(1); + source.onNext(2); + source.onNext(3); + + scheduler.advanceTimeBy(500, TimeUnit.MILLISECONDS); + + source.onComplete(); + + InOrder inOrder = inOrder(o); + inOrder.verify(o).onNext(1); + inOrder.verify(o).onNext(2); + inOrder.verify(o).onNext(3); + inOrder.verify(o).onComplete(); + inOrder.verifyNoMoreInteractions(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipTest.java index fbd5572246c..c1fe2bf2bcb 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,7 +27,7 @@ public class ObservableSkipTest extends RxJavaTest { - @Test + @Test(expected = IllegalArgumentException.class) public void skipNegativeElements() { Observable skip = Observable.just("one", "two", "three").skip(-99); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipTimedTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipTimedTest.java index 1c3fc30e147..83edc3201be 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipTimedTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipTimedTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipUntilTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipUntilTest.java index 290fc2c1f0d..bb2c3ef127e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipUntilTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipUntilTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipWhileTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipWhileTest.java index ab1abdfa49d..b6a0749088d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipWhileTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSkipWhileTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableStartWithTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableStartWithTest.java new file mode 100644 index 00000000000..267f5be42a4 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableStartWithTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.observable; + +import static org.mockito.Mockito.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; + +public class ObservableStartWithTest { + + @Test + public void justCompletableComplete() { + Observable.just(1).startWith(Completable.complete()) + .test() + .assertResult(1); + } + + @Test + public void emptyCompletableComplete() { + Observable.empty().startWith(Completable.complete()) + .test() + .assertResult(); + } + + @Test + public void runCompletableError() { + Runnable run = mock(Runnable.class); + + Observable.fromRunnable(run).startWith(Completable.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } + + @Test + public void justSingleJust() { + Observable.just(1).startWith(Single.just(2)) + .test() + .assertResult(2, 1); + } + + @Test + public void emptySingleJust() { + Runnable run = mock(Runnable.class); + + Observable.fromRunnable(run) + .startWith(Single.just(2)) + .test() + .assertResult(2); + + verify(run).run(); + } + + @Test + public void runSingleError() { + Runnable run = mock(Runnable.class); + + Observable.fromRunnable(run).startWith(Single.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } + + @Test + public void justMaybeJust() { + Observable.just(1).startWith(Maybe.just(2)) + .test() + .assertResult(2, 1); + } + + @Test + public void emptyMaybeJust() { + Runnable run = mock(Runnable.class); + + Observable.fromRunnable(run) + .startWith(Maybe.just(2)) + .test() + .assertResult(2); + + verify(run).run(); + } + + @Test + public void runMaybeError() { + Runnable run = mock(Runnable.class); + + Observable.fromRunnable(run).startWith(Maybe.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } + + @Test + public void justObservableJust() { + Observable.just(1).startWith(Observable.just(2, 3, 4, 5)) + .test() + .assertResult(2, 3, 4, 5, 1); + } + + @Test + public void emptyObservableJust() { + Runnable run = mock(Runnable.class); + + Observable.fromRunnable(run) + .startWith(Observable.just(2, 3, 4, 5)) + .test() + .assertResult(2, 3, 4, 5); + + verify(run).run(); + } + + @Test + public void emptyObservableEmpty() { + Runnable run = mock(Runnable.class); + Runnable run2 = mock(Runnable.class); + + Observable.fromRunnable(run) + .startWith(Observable.fromRunnable(run2)) + .test() + .assertResult(); + + verify(run).run(); + verify(run2).run(); + } + + @Test + public void runObservableError() { + Runnable run = mock(Runnable.class); + + Observable.fromRunnable(run).startWith(Observable.error(new TestException())) + .test() + .assertFailure(TestException.class); + + verify(run, never()).run(); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSubscribeOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSubscribeOnTest.java index 53ccf2b3a69..ab3890dcc6c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSubscribeOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSubscribeOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchIfEmptyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchIfEmptyTest.java index 34e24d81cb3..5dd3703c674 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchIfEmptyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchIfEmptyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchTest.java index 88f43e74523..72e6c93bb85 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableSwitchTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,16 +24,17 @@ import org.junit.*; import org.mockito.InOrder; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.internal.schedulers.ImmediateThinScheduler; import io.reactivex.rxjava3.internal.util.ExceptionHelper; -import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.observers.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.*; import io.reactivex.rxjava3.subjects.PublishSubject; @@ -651,12 +652,6 @@ public SingleSource apply(Object v) throws Exception { .assertError(NullPointerException.class); } - @Test(expected = NullPointerException.class) - public void switchMapSingleMapperIsNull() { - Observable.just(0) - .switchMapSingle(null); - } - @Test public void switchMapSingleFunctionDoesntReturnSingle() { Observable.just(0) @@ -1256,4 +1251,206 @@ public Observable apply(Integer v) .test() .assertResult(10, 20); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeObservable(f -> f.switchMap(v -> Observable.never())); + } + + @Test + public void mainCompleteCancelRace() { + for (int i = 0; i < TestHelper.RACE_LONG_LOOPS; i++) { + AtomicReference> ref = new AtomicReference<>(); + Observable o = new Observable() { + @Override + protected void subscribeActual(@NonNull Observer observer) { + ref.set(observer); + } + }; + + TestObserver to = o.switchMap(v -> Observable.never()) + .test(); + + ref.get().onSubscribe(Disposable.empty()); + + TestHelper.race( + () -> ref.get().onComplete(), + () -> to.dispose() + ); + } + } + + @Test + public void mainCompleteInnerErrorRace() { + TestException ex = new TestException(); + + for (int i = 0; i < TestHelper.RACE_LONG_LOOPS; i++) { + AtomicReference> ref1 = new AtomicReference<>(); + Observable o1 = new Observable() { + @Override + protected void subscribeActual(@NonNull Observer observer) { + ref1.set(observer); + } + }; + AtomicReference> ref2 = new AtomicReference<>(); + Observable o2 = new Observable() { + @Override + protected void subscribeActual(@NonNull Observer observer) { + ref2.set(observer); + } + }; + + o1.switchMap(v -> o2) + .test(); + + ref1.get().onSubscribe(Disposable.empty()); + ref1.get().onNext(1); + ref2.get().onSubscribe(Disposable.empty()); + + TestHelper.race( + () -> ref1.get().onComplete(), + () -> ref2.get().onError(ex) + ); + } + } + + @Test + public void innerNoSubscriptionYet() { + AtomicReference> ref1 = new AtomicReference<>(); + Observable o1 = new Observable() { + @Override + protected void subscribeActual(@NonNull Observer observer) { + ref1.set(observer); + } + }; + AtomicReference> ref2 = new AtomicReference<>(); + Observable o2 = new Observable() { + @Override + protected void subscribeActual(@NonNull Observer observer) { + ref2.set(observer); + } + }; + + o1.switchMap(v -> o2) + .test(); + + ref1.get().onSubscribe(Disposable.empty()); + ref1.get().onNext(1); + ref1.get().onComplete(); + } + + @Test + public void switchDuringOnNext() { + PublishSubject ps = PublishSubject.create(); + + TestObserver to = ps.switchMap(v -> Observable.range(v, 5)) + .doOnNext(v -> { + if (v == 1) { + ps.onNext(2); + } + }) + .test(); + + ps.onNext(1); + + to + .assertValuesOnly(1, 2, 3, 4, 5, 6); + } + + @Test + public void mainCompleteWhileInnerActive() { + PublishSubject ps1 = PublishSubject.create(); + PublishSubject ps2 = PublishSubject.create(); + + TestObserver to = ps1.switchMapDelayError(v -> ps2) + .test(); + + ps1.onNext(1); + ps1.onComplete(); + + ps2.onComplete(); + + to.assertResult(); + } + + @Test + public void innerIgnoresCancelAndErrors() throws Throwable { + TestHelper.withErrorTracking(errors -> { + PublishSubject ps = PublishSubject.create(); + + TestObserver to = ps + .switchMap(v -> { + if (v == 1) { + return Observable.unsafeCreate(s -> { + s.onSubscribe(Disposable.empty()); + ps.onNext(2); + s.onError(new TestException()); + }); + } + return Observable.never(); + }) + .test(); + + ps.onNext(1); + + to.assertEmpty(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void cancellationShouldTriggerInnerCancellationRace() throws Throwable { + AtomicInteger outer = new AtomicInteger(); + AtomicInteger inner = new AtomicInteger(); + + int n = 10_000; + for (int i = 0; i < n; i++) { + Observable.create(it -> { + it.onNext(0); + }) + .switchMap(v -> createObservable(inner)) + .observeOn(Schedulers.computation()) + .doFinally(() -> { + outer.incrementAndGet(); + }) + .take(1) + .blockingSubscribe(v -> { }, Throwable::printStackTrace); + } + + Thread.sleep(100); + assertEquals(inner.get(), outer.get()); + assertEquals(n, inner.get()); + } + + Observable createObservable(AtomicInteger inner) { + return Observable.unsafeCreate(s -> { + SerializedObserver it = new SerializedObserver<>(s); + it.onSubscribe(Disposable.empty()); + Schedulers.io().scheduleDirect(() -> { + it.onNext(1); + }, 0, TimeUnit.MILLISECONDS); + Schedulers.io().scheduleDirect(() -> { + it.onNext(2); + }, 0, TimeUnit.MILLISECONDS); + }) + .doFinally(() -> { + inner.incrementAndGet(); + }); + } + + @Test + public void innerOnSubscribeOuterCancelRace() { + TestObserver to = new TestObserver(); + + Observable.just(1) + .hide() + .switchMap(v -> Observable.just(1) + .doOnSubscribe(d -> to.dispose()) + .scan(1, (a, b) -> a) + ) + .subscribe(to); + + to.assertEmpty(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastOneTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastOneTest.java index 92536eb95e8..1bd19d6bc9a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastOneTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastOneTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastTest.java index 2aa9e37985e..f0a342e2e18 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -83,7 +83,7 @@ public void takeLastWithZeroCount() { verify(observer, times(1)).onComplete(); } - @Test(expected = IndexOutOfBoundsException.class) + @Test(expected = IllegalArgumentException.class) public void takeLastWithNegativeCount() { Observable.just("one").takeLast(-1); } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastTimedTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastTimedTest.java index a81fd1d9cb5..4e2bd6a5c06 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastTimedTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeLastTimedTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,7 +30,7 @@ public class ObservableTakeLastTimedTest extends RxJavaTest { - @Test(expected = IndexOutOfBoundsException.class) + @Test(expected = IllegalArgumentException.class) public void takeLastTimedWithNegativeCount() { Observable.just("one").takeLast(-1, 1, TimeUnit.SECONDS); } @@ -300,4 +300,9 @@ public void lastWindowIsFixedInTime() { to.assertResult(1, 2, 3, 4); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeObservable(o -> o.takeLast(1, TimeUnit.SECONDS)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeTest.java index f83fb8595d3..0ecff804460 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -34,7 +34,7 @@ import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subjects.PublishSubject; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class ObservableTakeTest extends RxJavaTest { @@ -111,6 +111,7 @@ public Integer apply(Integer t1) { } @Test + @SuppressUndeliverable public void takeDoesntLeakErrors() { Observable source = Observable.unsafeCreate(new ObservableSource() { @Override diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeTimedTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeTimedTest.java index 32f6049afbc..7edbfbcf20d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeTimedTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeTimedTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntilPredicateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntilPredicateTest.java index 143fe9d3cac..04d0ab55377 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntilPredicateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntilPredicateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntilTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntilTest.java index 5e831b03b3b..4bbf042acc4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntilTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeUntilTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeWhileTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeWhileTest.java index 134e1f93f63..0a9fc271368 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeWhileTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTakeWhileTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -100,6 +100,7 @@ public boolean test(String input) { } @Test + @SuppressUndeliverable public void takeWhileDoesntLeakErrors() { Observable source = Observable.unsafeCreate(new ObservableSource() { @Override diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleFirstTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleFirstTest.java index c8eedc72bda..fe296d572bc 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleFirstTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleFirstTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,16 +16,15 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; -import java.util.List; import java.util.concurrent.TimeUnit; -import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.functions.Action; import org.junit.*; import org.mockito.InOrder; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; -import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.TestScheduler; import io.reactivex.rxjava3.subjects.PublishSubject; import io.reactivex.rxjava3.testsupport.TestHelper; @@ -43,6 +42,76 @@ public void before() { observer = TestHelper.mockObserver(); } + @Test + public void throttlingWithDropCallbackCrashes() throws Throwable { + Observable source = Observable.unsafeCreate(new ObservableSource() { + @Override + public void subscribe(Observer innerObserver) { + innerObserver.onSubscribe(Disposable.empty()); + publishNext(innerObserver, 100, "one"); // publish as it's first + publishNext(innerObserver, 300, "two"); // skip as it's last within the first 400 + publishNext(innerObserver, 900, "three"); // publish + publishNext(innerObserver, 905, "four"); // skip + publishCompleted(innerObserver, 1000); // Should be published as soon as the timeout expires. + } + }); + + Action whenDisposed = mock(Action.class); + Observable sampled = source + .doOnDispose(whenDisposed) + .throttleFirst(400, TimeUnit.MILLISECONDS, scheduler, e -> { + if ("two".equals(e)) { + throw new TestException("forced"); + } + }); + sampled.subscribe(observer); + + InOrder inOrder = inOrder(observer); + + scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("one"); + inOrder.verify(observer, times(1)).onError(any(TestException.class)); + inOrder.verify(observer, times(0)).onNext("two"); + inOrder.verify(observer, times(0)).onNext("three"); + inOrder.verify(observer, times(0)).onNext("four"); + inOrder.verify(observer, times(0)).onComplete(); + inOrder.verifyNoMoreInteractions(); + verify(whenDisposed).run(); + } + + @Test + public void throttlingWithDropCallback() { + Observable source = Observable.unsafeCreate(new ObservableSource() { + @Override + public void subscribe(Observer innerObserver) { + innerObserver.onSubscribe(Disposable.empty()); + publishNext(innerObserver, 100, "one"); // publish as it's first + publishNext(innerObserver, 300, "two"); // skip as it's last within the first 400 + publishNext(innerObserver, 900, "three"); // publish + publishNext(innerObserver, 905, "four"); // skip + publishCompleted(innerObserver, 1000); // Should be published as soon as the timeout expires. + } + }); + + Observer dropCallbackObserver = TestHelper.mockObserver(); + Observable sampled = source.throttleFirst(400, TimeUnit.MILLISECONDS, scheduler, dropCallbackObserver::onNext); + sampled.subscribe(observer); + + InOrder inOrder = inOrder(observer); + InOrder dropCallbackOrder = inOrder(dropCallbackObserver); + + scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("one"); + inOrder.verify(observer, times(0)).onNext("two"); + dropCallbackOrder.verify(dropCallbackObserver, times(1)).onNext("two"); + inOrder.verify(observer, times(1)).onNext("three"); + inOrder.verify(observer, times(0)).onNext("four"); + dropCallbackOrder.verify(dropCallbackObserver, times(1)).onNext("four"); + inOrder.verify(observer, times(1)).onComplete(); + inOrder.verifyNoMoreInteractions(); + dropCallbackOrder.verifyNoMoreInteractions(); + } + @Test public void throttlingWithCompleted() { Observable source = Observable.unsafeCreate(new ObservableSource() { @@ -167,28 +236,7 @@ public void dispose() { } @Test - public void badSource() { - List errors = TestHelper.trackPluginErrors(); - try { - new Observable() { - @Override - protected void subscribeActual(Observer observer) { - observer.onSubscribe(Disposable.empty()); - observer.onNext(1); - observer.onNext(2); - observer.onComplete(); - observer.onNext(3); - observer.onError(new TestException()); - observer.onComplete(); - } - } - .throttleFirst(1, TimeUnit.DAYS) - .test() - .assertResult(1); - - TestHelper.assertUndeliverable(errors, 0, TestException.class); - } finally { - RxJavaPlugins.reset(); - } + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeObservable(o -> o.throttleFirst(1, TimeUnit.SECONDS)); } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleLatestTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleLatestTest.java index 5399f63fce4..e1c15f3b1a1 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleLatestTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableThrottleLatestTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,12 +20,13 @@ import org.junit.Test; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.schedulers.TestScheduler; import io.reactivex.rxjava3.subjects.PublishSubject; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class ObservableThrottleLatestTest extends RxJavaTest { @@ -221,4 +222,424 @@ public void onNext(Integer t) { to.assertResult(1, 2); } + + /** Emit 1, 2, 3, then advance time by a second; 1 and 3 should end up in downstream, 2 should be dropped. */ + @Test + public void onDroppedBasicNoEmitLast() { + PublishSubject ps = PublishSubject.create(); + + TestScheduler sch = new TestScheduler(); + + TestObserver drops = new TestObserver<>(); + drops.onSubscribe(Disposable.empty()); + + TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .test(); + + to.assertEmpty(); + drops.assertEmpty(); + + ps.onNext(1); + + to.assertValuesOnly(1); + drops.assertEmpty(); + + ps.onNext(2); + + to.assertValuesOnly(1); + drops.assertEmpty(); + + ps.onNext(3); + + to.assertValuesOnly(1); + drops.assertValuesOnly(2); + + sch.advanceTimeBy(1, TimeUnit.SECONDS); + + to.assertValuesOnly(1, 3); + drops.assertValuesOnly(2); + + ps.onComplete(); + + to.assertResult(1, 3); + + drops.assertValuesOnly(2); + } + + /** Emit 1, 2, 3; 1 should end up in downstream, 2, 3 should be dropped. */ + @Test + public void onDroppedBasicNoEmitLastDropLast() { + PublishSubject ps = PublishSubject.create(); + + TestScheduler sch = new TestScheduler(); + + TestObserver drops = new TestObserver<>(); + drops.onSubscribe(Disposable.empty()); + + TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .test(); + + to.assertEmpty(); + drops.assertEmpty(); + + ps.onNext(1); + + to.assertValuesOnly(1); + drops.assertEmpty(); + + ps.onNext(2); + + to.assertValuesOnly(1); + drops.assertEmpty(); + + ps.onNext(3); + + to.assertValuesOnly(1); + drops.assertValuesOnly(2); + + ps.onComplete(); + + to.assertResult(1); + + drops.assertValuesOnly(2, 3); + } + + /** Emit 1, 2, 3; 1 and 3 should end up in downstream, 2 should be dropped. */ + @Test + public void onDroppedBasicEmitLast() { + PublishSubject ps = PublishSubject.create(); + + TestScheduler sch = new TestScheduler(); + + TestObserver drops = new TestObserver<>(); + drops.onSubscribe(Disposable.empty()); + + TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, true, drops::onNext) + .test(); + + to.assertEmpty(); + drops.assertEmpty(); + + ps.onNext(1); + + to.assertValuesOnly(1); + drops.assertEmpty(); + + ps.onNext(2); + + to.assertValuesOnly(1); + drops.assertEmpty(); + + ps.onNext(3); + + to.assertValuesOnly(1); + drops.assertValuesOnly(2); + + ps.onComplete(); + + to.assertResult(1, 3); + + drops.assertValuesOnly(2); + } + + /** Emit 1, 2, 3; 3 should trigger an error to the downstream because 2 is dropped and the callback crashes. */ + @Test + public void onDroppedBasicNoEmitLastFirstDropCrash() throws Throwable { + PublishSubject ps = PublishSubject.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestObserver to = ps + .doOnDispose(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { + if (d == 2) { + throw new TestException("forced"); + } + }) + .test(); + + to.assertEmpty(); + + ps.onNext(1); + + to.assertValuesOnly(1); + + ps.onNext(2); + + to.assertValuesOnly(1); + + ps.onNext(3); + + to.assertFailure(TestException.class, 1); + + verify(whenDisposed).run(); + } + + /** + * Emit 1, 2, Error; the error should trigger the drop callback and crash it too, + * downstream gets 1, composite(source, drop-crash). + */ + @Test + public void onDroppedBasicNoEmitLastOnErrorDropCrash() throws Throwable { + PublishSubject ps = PublishSubject.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestObserverEx to = ps + .doOnDispose(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .subscribeWith(new TestObserverEx<>()); + + to.assertEmpty(); + + ps.onNext(1); + + to.assertValuesOnly(1); + + ps.onNext(2); + + to.assertValuesOnly(1); + + ps.onError(new TestException("source")); + + to.assertFailure(CompositeException.class, 1); + + TestHelper.assertCompositeExceptions(to, TestException.class, "source", TestException.class, "forced 2"); + + verify(whenDisposed, never()).run(); + } + + /** + * Emit 1, 2, 3; 3 should trigger a drop-crash for 2, which then would trigger the error path and drop-crash for 3, + * the last item not delivered, downstream gets 1, composite(drop-crash 2, drop-crash 3). + */ + @Test + public void onDroppedBasicEmitLastOnErrorDropCrash() throws Throwable { + PublishSubject ps = PublishSubject.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestObserverEx to = ps + .doOnDispose(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, true, d -> { throw new TestException("forced " + d); }) + .subscribeWith(new TestObserverEx<>()); + + to.assertEmpty(); + + ps.onNext(1); + + to.assertValuesOnly(1); + + ps.onNext(2); + + to.assertValuesOnly(1); + + ps.onNext(3); + + to.assertFailure(CompositeException.class, 1); + + TestHelper.assertCompositeExceptions(to, TestException.class, "forced 2", TestException.class, "forced 3"); + + verify(whenDisposed).run(); + } + + /** Emit 1, complete; Downstream gets 1, complete, no drops. */ + @Test + public void onDroppedBasicNoEmitLastNoLastToDrop() { + PublishSubject ps = PublishSubject.create(); + + TestScheduler sch = new TestScheduler(); + + TestObserver drops = new TestObserver<>(); + drops.onSubscribe(Disposable.empty()); + + TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .test(); + + to.assertEmpty(); + drops.assertEmpty(); + + ps.onNext(1); + + to.assertValuesOnly(1); + drops.assertEmpty(); + + ps.onComplete(); + + to.assertResult(1); + drops.assertEmpty(); + } + + /** Emit 1, error; Downstream gets 1, error, no drops. */ + @Test + public void onDroppedErrorNoEmitLastNoLastToDrop() { + PublishSubject ps = PublishSubject.create(); + + TestScheduler sch = new TestScheduler(); + + TestObserver drops = new TestObserver<>(); + drops.onSubscribe(Disposable.empty()); + + TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .test(); + + to.assertEmpty(); + drops.assertEmpty(); + + ps.onNext(1); + + to.assertValuesOnly(1); + drops.assertEmpty(); + + ps.onError(new TestException()); + + to.assertFailure(TestException.class, 1); + drops.assertEmpty(); + } + + /** + * Emit 1, 2, complete; complete should crash drop, downstream gets 1, drop-crash 2. + */ + @Test + public void onDroppedHasLastNoEmitLastDropCrash() throws Throwable { + PublishSubject ps = PublishSubject.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestObserverEx to = ps + .doOnDispose(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .subscribeWith(new TestObserverEx<>()); + + to.assertEmpty(); + + ps.onNext(1); + + to.assertValuesOnly(1); + + ps.onNext(2); + + to.assertValuesOnly(1); + + ps.onComplete(); + + to.assertFailureAndMessage(TestException.class, "forced 2", 1); + + verify(whenDisposed, never()).run(); + } + + /** + * Emit 1, 2 then dispose the sequence; downstream gets 1, drop should get for 2. + */ + @Test + public void onDroppedDisposeDrops() throws Throwable { + PublishSubject ps = PublishSubject.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestObserver drops = new TestObserver<>(); + drops.onSubscribe(Disposable.empty()); + + TestObserverEx to = ps + .doOnDispose(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .subscribeWith(new TestObserverEx<>()); + + to.assertEmpty(); + + ps.onNext(1); + + to.assertValuesOnly(1); + + ps.onNext(2); + + to.assertValuesOnly(1); + + to.dispose(); + + to.assertValuesOnly(1); + drops.assertValuesOnly(2); + + verify(whenDisposed).run(); + } + + /** + * Emit 1 then dispose the sequence; downstream gets 1, drop should not get called. + */ + @Test + public void onDroppedDisposeNoDrops() throws Throwable { + PublishSubject ps = PublishSubject.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestObserver drops = new TestObserver<>(); + drops.onSubscribe(Disposable.empty()); + + TestObserverEx to = ps + .doOnDispose(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .subscribeWith(new TestObserverEx<>()); + + to.assertEmpty(); + + ps.onNext(1); + + to.assertValuesOnly(1); + + to.dispose(); + + to.assertValuesOnly(1); + drops.assertEmpty(); + + verify(whenDisposed).run(); + } + + /** + * Emit 1, 2 then dispose the sequence; downstream gets 1, global error handler should get drop-crash 2. + */ + @Test + public void onDroppedDisposeCrashesDrop() throws Throwable { + TestHelper.withErrorTracking(errors -> { + PublishSubject ps = PublishSubject.create(); + + TestScheduler sch = new TestScheduler(); + + Action whenDisposed = mock(Action.class); + + TestObserverEx to = ps + .doOnDispose(whenDisposed) + .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .subscribeWith(new TestObserverEx<>()); + + to.assertEmpty(); + + ps.onNext(1); + + to.assertValuesOnly(1); + + ps.onNext(2); + + to.assertValuesOnly(1); + + to.dispose(); + + to.assertValuesOnly(1); + + verify(whenDisposed).run(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class, "forced 2"); + }); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeIntervalTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeIntervalTest.java index 5f935791b1c..ce418200d8e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeIntervalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeIntervalTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeoutTests.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeoutTests.java index fe7b2cd3707..570eb3de5e0 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeoutTests.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeoutTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeoutWithSelectorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeoutWithSelectorTest.java index 60cb5a8b927..2c6710cc896 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeoutWithSelectorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimeoutWithSelectorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -40,6 +40,7 @@ import io.reactivex.rxjava3.testsupport.*; public class ObservableTimeoutWithSelectorTest extends RxJavaTest { + @Test public void timeoutSelectorNormal1() { PublishSubject source = PublishSubject.create(); @@ -493,6 +494,7 @@ public void withOtherMainError() { } @Test + @SuppressUndeliverable public void badSourceTimeout() { new Observable() { @Override diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimerTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimerTest.java index 8eddbce491d..9229d24fe3b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimerTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -317,7 +317,7 @@ public void timerDelayZero() { public void timerInterruptible() throws Exception { ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); try { - for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec) }) { + for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec, true) }) { final AtomicBoolean interrupted = new AtomicBoolean(); TestObserver to = Observable.timer(1, TimeUnit.MILLISECONDS, s) .map(new Function() { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimestampTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimestampTest.java index 597333ea66b..084db674738 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimestampTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableTimestampTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToFutureTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToFutureTest.java index 164d7f6fd68..0ac13be46ab 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToFutureTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToFutureTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -61,7 +61,7 @@ public void successOperatesOnSuppliedScheduler() throws Exception { TestScheduler scheduler = new TestScheduler(); TestObserver to = new TestObserver<>(o); - Observable.fromFuture(future, scheduler).subscribe(to); + Observable.fromFuture(future).subscribeOn(scheduler).subscribe(to); verify(o, never()).onNext(value); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToListTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToListTest.java index 020183f9fac..2d4185407da 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToListTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToListTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToMapTest.java index 8838ff4b5a5..72b39d0025c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToMultimapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToMultimapTest.java index 0853b0acadd..10bda16080f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToMultimapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToMultimapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToSortedListTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToSortedListTest.java index 19c10c6622b..0ea0be21b9e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToSortedListTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToSortedListTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToXTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToXTest.java index 1afbba02254..c7cc6f31515 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToXTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableToXTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUnsubscribeOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUnsubscribeOnTest.java index da58ffdb2a3..23f6d7256bf 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUnsubscribeOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUnsubscribeOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,6 +26,7 @@ import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Action; +import io.reactivex.rxjava3.internal.schedulers.ImmediateThinScheduler; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.testsupport.*; @@ -265,4 +266,9 @@ protected void subscribeActual(Observer observer) { RxJavaPlugins.reset(); } } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeObservable(o -> o.unsubscribeOn(ImmediateThinScheduler.INSTANCE)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUsingTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUsingTest.java index 143524319d1..de8d73fa36d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUsingTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableUsingTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithObservableTest.java index bfb972626bc..edfca3989d9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -586,6 +586,7 @@ public void run() { } @Test + @SuppressUndeliverable public void disposeMainBoundaryErrorRace() { final TestException ex = new TestException(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithSizeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithSizeTest.java index 04099c31cba..81d076e718a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithSizeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithSizeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -535,4 +535,94 @@ public void accept(Observable v) throws Throwable { inner.get().test().assertResult(1); } + + @Test + public void cancelWithoutWindowSize() { + PublishSubject ps = PublishSubject.create(); + + TestObserver> to = ps.window(10) + .test(); + + assertTrue(ps.hasObservers()); + + to.dispose(); + + assertFalse("Subject still has observers!", ps.hasObservers()); + } + + @Test + public void cancelAfterAbandonmentSize() { + PublishSubject ps = PublishSubject.create(); + + TestObserver> to = ps.window(10) + .test(); + + assertTrue(ps.hasObservers()); + + ps.onNext(1); + + to.dispose(); + + assertFalse("Subject still has observers!", ps.hasObservers()); + } + + @Test + public void cancelWithoutWindowSkip() { + PublishSubject ps = PublishSubject.create(); + + TestObserver> to = ps.window(10, 15) + .test(); + + assertTrue(ps.hasObservers()); + + to.dispose(); + + assertFalse("Subject still has observers!", ps.hasObservers()); + } + + @Test + public void cancelAfterAbandonmentSkip() { + PublishSubject ps = PublishSubject.create(); + + TestObserver> to = ps.window(10, 15) + .test(); + + assertTrue(ps.hasObservers()); + + ps.onNext(1); + + to.dispose(); + + assertFalse("Subject still has observers!", ps.hasObservers()); + } + + @Test + public void cancelWithoutWindowOverlap() { + PublishSubject ps = PublishSubject.create(); + + TestObserver> to = ps.window(10, 5) + .test(); + + assertTrue(ps.hasObservers()); + + to.dispose(); + + assertFalse("Subject still has observers!", ps.hasObservers()); + } + + @Test + public void cancelAfterAbandonmentOverlap() { + PublishSubject ps = PublishSubject.create(); + + TestObserver> to = ps.window(10, 5) + .test(); + + assertTrue(ps.hasObservers()); + + ps.onNext(1); + + to.dispose(); + + assertFalse("Subject still has observers!", ps.hasObservers()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithStartEndObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithStartEndObservableTest.java index af67c36bf2e..659daaf7d1e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithStartEndObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithStartEndObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,16 +15,17 @@ import static org.junit.Assert.*; +import java.io.IOException; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.*; -import io.reactivex.rxjava3.disposables.Disposable; import org.junit.*; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; @@ -32,7 +33,7 @@ import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.TestScheduler; import io.reactivex.rxjava3.subjects.*; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class ObservableWindowWithStartEndObservableTest extends RxJavaTest { @@ -289,6 +290,7 @@ public ObservableSource apply(Integer v) throws Exception { } @Test + @SuppressUndeliverable public void endError() { PublishSubject source = PublishSubject.create(); PublishSubject start = PublishSubject.create(); @@ -530,4 +532,174 @@ public void mainError() { .test() .assertFailure(TestException.class); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeObservable(o -> o.window(Observable.never(), v -> Observable.never())); + } + + @Test + public void openError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + TestException ex1 = new TestException(); + TestException ex2 = new TestException(); + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + AtomicReference> ref1 = new AtomicReference<>(); + AtomicReference> ref2 = new AtomicReference<>(); + + Observable o1 = Observable.unsafeCreate(ref1::set); + Observable o2 = Observable.unsafeCreate(ref2::set); + + TestObserver> to = BehaviorSubject.createDefault(1) + .window(o1, v -> o2) + .doOnNext(w -> w.test()) + .test(); + + ref1.get().onSubscribe(Disposable.empty()); + ref1.get().onNext(1); + ref2.get().onSubscribe(Disposable.empty()); + + TestHelper.race( + () -> ref1.get().onError(ex1), + () -> ref2.get().onError(ex2) + ); + + to.assertError(RuntimeException.class); + + if (!errors.isEmpty()) { + TestHelper.assertUndeliverable(errors, 0, TestException.class); + } + + errors.clear(); + } + }); + } + + @Test + public void closeError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + AtomicReference> ref1 = new AtomicReference<>(); + AtomicReference> ref2 = new AtomicReference<>(); + + Observable o1 = Observable.unsafeCreate(ref1::set); + Observable o2 = Observable.unsafeCreate(ref2::set); + + TestObserver to = BehaviorSubject.createDefault(1) + .window(o1, v -> o2) + .flatMap(v -> v) + .test(); + + ref1.get().onSubscribe(Disposable.empty()); + ref1.get().onNext(1); + ref2.get().onSubscribe(Disposable.empty()); + + ref2.get().onError(new TestException()); + ref2.get().onError(new TestException()); + + to.assertFailure(TestException.class); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void upstreamFailsBeforeFirstWindow() { + Observable.error(new TestException()) + .window(Observable.never(), v -> Observable.never()) + .test() + .assertFailure(TestException.class); + } + + @Test + public void windowOpenMainCompletes() { + AtomicReference> ref1 = new AtomicReference<>(); + + PublishSubject ps = PublishSubject.create(); + Observable o1 = Observable.unsafeCreate(ref1::set); + + AtomicInteger counter = new AtomicInteger(); + + TestObserver> to = ps + .window(o1, v -> Observable.never()) + .doOnNext(w -> { + if (counter.getAndIncrement() == 0) { + ref1.get().onNext(2); + ps.onNext(1); + ps.onComplete(); + } + w.test(); + }) + .test(); + + ref1.get().onSubscribe(Disposable.empty()); + ref1.get().onNext(1); + + to.assertComplete(); + } + + @Test + public void windowOpenMainError() { + AtomicReference> ref1 = new AtomicReference<>(); + + PublishSubject ps = PublishSubject.create(); + Observable o1 = Observable.unsafeCreate(ref1::set); + + AtomicInteger counter = new AtomicInteger(); + + TestObserver> to = ps + .window(o1, v -> Observable.never()) + .doOnNext(w -> { + if (counter.getAndIncrement() == 0) { + ref1.get().onNext(2); + ps.onNext(1); + ps.onError(new TestException()); + } + w.test(); + }) + .test(); + + ref1.get().onSubscribe(Disposable.empty()); + ref1.get().onNext(1); + + to.assertError(TestException.class); + } + + @Test + public void windowOpenIgnoresDispose() { + AtomicReference> ref1 = new AtomicReference<>(); + + PublishSubject ps = PublishSubject.create(); + Observable o1 = Observable.unsafeCreate(ref1::set); + + TestObserver> to = ps + .window(o1, v -> Observable.never()) + .take(1) + .doOnNext(w -> { + w.test(); + }) + .test(); + + ref1.get().onSubscribe(Disposable.empty()); + ref1.get().onNext(1); + ref1.get().onNext(2); + + to.assertValueCount(1); + } + + @Test + public void mainIgnoresCancelBeforeOnError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Observable.unsafeCreate(s -> { + s.onSubscribe(Disposable.empty()); + s.onNext(1); + s.onError(new IOException()); + }) + .window(BehaviorSubject.createDefault(1), v -> Observable.error(new TestException())) + .doOnNext(w -> w.test()) + .test() + .assertError(TestException.class); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + }); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithTimeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithTimeTest.java index 13f662c88ee..ca8f90d04fa 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithTimeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWindowWithTimeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,19 +19,19 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.*; -import io.reactivex.rxjava3.disposables.Disposable; import org.junit.*; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.observers.*; import io.reactivex.rxjava3.schedulers.*; import io.reactivex.rxjava3.subjects.*; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class ObservableWindowWithTimeTest extends RxJavaTest { @@ -368,6 +368,7 @@ public void timeskipOverlapping() { } @Test + @SuppressUndeliverable public void exactOnError() { TestScheduler scheduler = new TestScheduler(); @@ -383,6 +384,7 @@ public void exactOnError() { } @Test + @SuppressUndeliverable public void overlappingOnError() { TestScheduler scheduler = new TestScheduler(); @@ -398,6 +400,7 @@ public void overlappingOnError() { } @Test + @SuppressUndeliverable public void skipOnError() { TestScheduler scheduler = new TestScheduler(); @@ -434,6 +437,7 @@ public void restartTimer() { } @Test + @SuppressUndeliverable public void exactBoundaryError() { Observable.error(new TestException()) .window(1, TimeUnit.DAYS, Schedulers.single(), 2, true) @@ -751,6 +755,7 @@ public void accept(Observable v) throws Exception { } @Test + @SuppressUndeliverable public void exactTimeBoundNoInterruptWindowOutputOnError() throws Exception { final AtomicBoolean isInterrupted = new AtomicBoolean(); @@ -831,6 +836,7 @@ public void accept(Observable v) throws Exception { } @Test + @SuppressUndeliverable public void exactTimeAndSizeBoundNoInterruptWindowOutputOnError() throws Exception { final AtomicBoolean isInterrupted = new AtomicBoolean(); @@ -911,6 +917,7 @@ public void accept(Observable v) throws Exception { } @Test + @SuppressUndeliverable public void skipTimeAndSizeBoundNoInterruptWindowOutputOnError() throws Exception { final AtomicBoolean isInterrupted = new AtomicBoolean(); @@ -1099,4 +1106,26 @@ public void accept(Observable v) throws Throwable { inner.get().test().assertResult(); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeObservable(o -> o.window(1, TimeUnit.SECONDS)); + } + + @Test + public void timedBoundarySignalAndDisposeRace() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + TestScheduler scheduler = new TestScheduler(); + + PublishSubject ps = PublishSubject.create(); + + TestObserver> to = ps.window(1, TimeUnit.MINUTES, scheduler, 1) + .test(); + + TestHelper.race( + () -> ps.onNext(1), + () -> to.dispose() + ); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWithLatestFromTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWithLatestFromTest.java index c23c41fde1e..cfe093ed6b5 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWithLatestFromTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableWithLatestFromTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipCompletionTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipCompletionTest.java index 76d14495db9..89dde2cdc52 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipCompletionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipCompletionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipIterableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipIterableTest.java index a4ce20c33cf..ce4ee90939f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipIterableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipIterableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipTest.java index d481c16662d..faebee3fa55 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/observable/ObservableZipTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -1403,7 +1403,7 @@ public Integer apply(Integer t1, Integer t2) throws Exception { public void firstErrorPreventsSecondSubscription() { final AtomicInteger counter = new AtomicInteger(); - List> observableList = new ArrayList<>(); + List> observableList = new ArrayList<>(); observableList.add(Observable.create(new ObservableOnSubscribe() { @Override public void subscribe(ObservableEmitter e) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleAmbTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleAmbTest.java index acfa6528a6d..8086aa7c1ca 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleAmbTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleAmbTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -249,7 +249,8 @@ public void run() { @Test public void manySources() { - Single[] sources = new Single[32]; + @SuppressWarnings("unchecked") + Single[] sources = new Single[32]; Arrays.fill(sources, Single.never()); sources[31] = Single.just(31); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleBlockingSubscribeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleBlockingSubscribeTest.java new file mode 100644 index 00000000000..a29c10975f5 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleBlockingSubscribeTest.java @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Single; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class SingleBlockingSubscribeTest { + + @Test + public void noArgSuccess() { + Single.just(1) + .blockingSubscribe(); + } + + @Test + public void noArgSuccessAsync() { + Single.just(1) + .delay(100, TimeUnit.MILLISECONDS) + .blockingSubscribe(); + } + + @Test + public void noArgError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Single.error(new TestException()) + .blockingSubscribe(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void noArgErrorAsync() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Single.error(new TestException()) + .delay(100, TimeUnit.MILLISECONDS, Schedulers.computation(), true) + .blockingSubscribe(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void oneArgSuccess() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + + Single.just(1) + .blockingSubscribe(success); + + verify(success).accept(1); + } + + @Test + public void oneArgSuccessAsync() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + + Single.just(1) + .delay(50, TimeUnit.MILLISECONDS) + .blockingSubscribe(success); + + verify(success).accept(1); + } + + @Test + public void oneArgSuccessFails() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + doThrow(new TestException()).when(success).accept(any()); + + Single.just(1) + .blockingSubscribe(success); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(success).accept(1); + }); + } + + @Test + public void oneArgError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + + Single.error(new TestException()) + .blockingSubscribe(success); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(success, never()).accept(any()); + }); + } + + @Test + public void oneArgErrorAsync() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + + Single.error(new TestException()) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation(), true) + .blockingSubscribe(success); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(success, never()).accept(any()); + }); + } + + @Test + public void twoArgSuccess() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Single.just(1) + .blockingSubscribe(success, consumer); + + verify(success).accept(1); + verify(consumer, never()).accept(any()); + } + + @Test + public void twoArgSuccessAsync() throws Throwable { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Single.just(1) + .delay(50, TimeUnit.MILLISECONDS) + .blockingSubscribe(success, consumer); + + verify(success).accept(any()); + verify(consumer, never()).accept(any()); + } + + @Test + public void twoArgSuccessFails() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + doThrow(new TestException()).when(success).accept(any()); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Single.just(1) + .blockingSubscribe(success, consumer); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(success).accept(any()); + verify(consumer, never()).accept(any()); + }); + } + + @Test + public void twoArgError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Single.error(new TestException()) + .blockingSubscribe(success, consumer); + + assertTrue("" + errors, errors.isEmpty()); + + verify(success, never()).accept(any()); + verify(consumer).accept(any(TestException.class)); + }); + } + + @Test + public void twoArgErrorAsync() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Single.error(new TestException()) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation(), true) + .blockingSubscribe(success, consumer); + + assertTrue("" + errors, errors.isEmpty()); + + verify(success, never()).accept(any()); + verify(consumer).accept(any(TestException.class)); + }); + } + + @Test + public void twoArgErrorFails() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + doThrow(new TestException()).when(consumer).accept(any()); + + Single.error(new TestException()) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation(), true) + .blockingSubscribe(success, consumer); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + + verify(success, never()).accept(any()); + verify(consumer).accept(any(TestException.class)); + }); + } + + @Test + public void twoArgInterrupted() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Action onDispose = mock(Action.class); + + @SuppressWarnings("unchecked") + Consumer success = mock(Consumer.class); + @SuppressWarnings("unchecked") + Consumer consumer = mock(Consumer.class); + + Thread.currentThread().interrupt(); + + Single.never() + .doOnDispose(onDispose) + .blockingSubscribe(success, consumer); + + assertTrue("" + errors, errors.isEmpty()); + + verify(onDispose).run(); + verify(success, never()).accept(any()); + verify(consumer).accept(any(InterruptedException.class)); + }); + } + + @Test + public void observerSuccess() { + TestObserver to = new TestObserver<>(); + + Single.just(1) + .blockingSubscribe(to); + + to.assertResult(1); + } + + @Test + public void observerSuccessAsync() { + TestObserver to = new TestObserver<>(); + + Single.just(1) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation(), true) + .blockingSubscribe(to); + + to.assertResult(1); + } + + @Test + public void observerError() { + TestObserver to = new TestObserver<>(); + + Single.error(new TestException()) + .blockingSubscribe(to); + + to.assertFailure(TestException.class); + } + + @Test + public void observerErrorAsync() { + TestObserver to = new TestObserver<>(); + + Single.error(new TestException()) + .delay(50, TimeUnit.MILLISECONDS, Schedulers.computation(), true) + .blockingSubscribe(to); + + to.assertFailure(TestException.class); + } + + @Test + public void observerDispose() throws Throwable { + Action onDispose = mock(Action.class); + + TestObserver to = new TestObserver<>(); + to.dispose(); + + Single.never() + .doOnDispose(onDispose) + .blockingSubscribe(to); + + to.assertEmpty(); + + verify(onDispose).run(); + } + + @Test + public void ovserverInterrupted() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Action onDispose = mock(Action.class); + + TestObserver to = new TestObserver<>(); + + Thread.currentThread().interrupt(); + + Single.never() + .doOnDispose(onDispose) + .blockingSubscribe(to); + + assertTrue("" + errors, errors.isEmpty()); + + verify(onDispose).run(); + to.assertFailure(InterruptedException.class); + }); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleCacheTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleCacheTest.java index 28eb94110b9..ca46a92f123 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleCacheTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleCacheTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatArrayDelayErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatArrayDelayErrorTest.java new file mode 100644 index 00000000000..00ff0d5ad13 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatArrayDelayErrorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Single; +import io.reactivex.rxjava3.exceptions.TestException; + +public class SingleConcatArrayDelayErrorTest { + + @Test + public void normal() { + Single.concatArrayDelayError( + Single.just(1), + Single.error(new TestException()), + Single.just(2) + ) + .test() + .assertFailure(TestException.class, 1, 2); + } + +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatArrayEagerDelayErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatArrayEagerDelayErrorTest.java new file mode 100644 index 00000000000..bfd96ad3a97 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatArrayEagerDelayErrorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Single; +import io.reactivex.rxjava3.exceptions.TestException; + +public class SingleConcatArrayEagerDelayErrorTest { + + @Test + public void normal() { + Single.concatArrayEagerDelayError( + Single.just(1), + Single.error(new TestException()), + Single.just(2) + ) + .test() + .assertFailure(TestException.class, 1, 2); + } + +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatDelayErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatDelayErrorTest.java new file mode 100644 index 00000000000..18dc2c83d2a --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatDelayErrorTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import java.util.Arrays; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; + +public class SingleConcatDelayErrorTest { + + @Test + public void normalIterable() { + Single.concatDelayError(Arrays.asList( + Single.just(1), + Single.error(new TestException()), + Single.just(2) + )) + .test() + .assertFailure(TestException.class, 1, 2); + } + + @Test + public void normalPublisher() { + Single.concatDelayError(Flowable.fromArray( + Single.just(1), + Single.error(new TestException()), + Single.just(2) + )) + .test() + .assertFailure(TestException.class, 1, 2); + } + + @Test + public void normalPublisherPrefetch() { + Single.concatDelayError(Flowable.fromArray( + Single.just(1), + Single.error(new TestException()), + Single.just(2) + ), 1) + .test() + .assertFailure(TestException.class, 1, 2); + } + +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatEagerTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatEagerTest.java new file mode 100644 index 00000000000..892ed8dd4d3 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatEagerTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import java.util.Arrays; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; + +public class SingleConcatEagerTest { + + @Test + public void iterableNormal() { + Single.concatEager(Arrays.asList( + Single.just(1), + Single.just(2) + )) + .test() + .assertResult(1, 2); + } + + @Test + public void iterableNormalMaxConcurrency() { + Single.concatEager(Arrays.asList( + Single.just(1), + Single.just(2) + ), 1) + .test() + .assertResult(1, 2); + } + + @Test + public void iterableError() { + Single.concatEager(Arrays.asList( + Single.just(1), + Single.error(new TestException()), + Single.just(2) + )) + .test() + .assertFailure(TestException.class, 1); + } + + @Test + public void iterableErrorMaxConcurrency() { + Single.concatEager(Arrays.asList( + Single.just(1), + Single.error(new TestException()), + Single.just(2) + ), 1) + .test() + .assertFailure(TestException.class, 1); + } + + @Test + public void publisherNormal() { + Single.concatEager(Flowable.fromArray( + Single.just(1), + Single.just(2) + )) + .test() + .assertResult(1, 2); + } + + @Test + public void publisherNormalMaxConcurrency() { + Single.concatEager(Flowable.fromArray( + Single.just(1), + Single.just(2) + ), 1) + .test() + .assertResult(1, 2); + } + + @Test + public void publisherError() { + Single.concatEager(Flowable.fromArray( + Single.just(1), + Single.error(new TestException()), + Single.just(2) + )) + .test() + .assertFailure(TestException.class, 1); + } + + @Test + public void iterableDelayError() { + Single.concatEagerDelayError(Arrays.asList( + Single.just(1), + Single.error(new TestException()), + Single.just(2) + )) + .test() + .assertFailure(TestException.class, 1, 2); + } + + @Test + public void iterableDelayErrorMaxConcurrency() { + Single.concatEagerDelayError(Arrays.asList( + Single.just(1), + Single.error(new TestException()), + Single.just(2) + ), 1) + .test() + .assertFailure(TestException.class, 1, 2); + } + + @Test + public void publisherDelayError() { + Single.concatEagerDelayError(Flowable.fromArray( + Single.just(1), + Single.error(new TestException()), + Single.just(2) + )) + .test() + .assertFailure(TestException.class, 1, 2); + } + + @Test + public void publisherDelayErrorMaxConcurrency() { + Single.concatEagerDelayError(Flowable.fromArray( + Single.just(1), + Single.error(new TestException()), + Single.just(2) + ), 1) + .test() + .assertFailure(TestException.class, 1, 2); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatMapCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatMapCompletableTest.java new file mode 100644 index 00000000000..3c603b26b9f --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatMapCompletableTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class SingleConcatMapCompletableTest extends RxJavaTest { + + @Test + public void dispose() { + TestHelper.checkDisposed(Single.just(1).concatMapCompletable(new Function() { + @Override + public Completable apply(Integer v) throws Exception { + return Completable.complete(); + } + })); + } + + @Test + public void normal() { + final boolean[] b = { false }; + + Single.just(1) + .concatMapCompletable(new Function() { + @Override + public Completable apply(Integer t) throws Exception { + return Completable.complete().doOnComplete(new Action() { + @Override + public void run() throws Exception { + b[0] = true; + } + }); + } + }) + .test() + .assertResult(); + + assertTrue(b[0]); + } + + @Test + public void error() { + final boolean[] b = { false }; + + Single.error(new TestException()) + .concatMapCompletable(new Function() { + @Override + public Completable apply(Integer t) throws Exception { + return Completable.complete().doOnComplete(new Action() { + @Override + public void run() throws Exception { + b[0] = true; + } + }); + } + }) + .test() + .assertFailure(TestException.class); + + assertFalse(b[0]); + } + + @Test + public void mapperThrows() { + final boolean[] b = { false }; + + Single.just(1) + .concatMapCompletable(new Function() { + @Override + public Completable apply(Integer t) throws Exception { + throw new TestException(); + } + }) + .test() + .assertFailure(TestException.class); + + assertFalse(b[0]); + } + + @Test + public void mapperReturnsNull() { + final boolean[] b = { false }; + + Single.just(1) + .concatMapCompletable(new Function() { + @Override + public Completable apply(Integer t) throws Exception { + return null; + } + }) + .test() + .assertFailure(NullPointerException.class); + + assertFalse(b[0]); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatMapMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatMapMaybeTest.java new file mode 100644 index 00000000000..24710d824ad --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatMapMaybeTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class SingleConcatMapMaybeTest extends RxJavaTest { + @Test + public void concatMapMaybeValue() { + Single.just(1).concatMapMaybe(new Function>() { + @Override public MaybeSource apply(final Integer integer) throws Exception { + if (integer == 1) { + return Maybe.just(2); + } + + return Maybe.just(1); + } + }) + .test() + .assertResult(2); + } + + @Test + public void concatMapMaybeValueDifferentType() { + Single.just(1).concatMapMaybe(new Function>() { + @Override public MaybeSource apply(final Integer integer) throws Exception { + if (integer == 1) { + return Maybe.just("2"); + } + + return Maybe.just("1"); + } + }) + .test() + .assertResult("2"); + } + + @Test + public void concatMapMaybeValueNull() { + Single.just(1).concatMapMaybe(new Function>() { + @Override public MaybeSource apply(final Integer integer) throws Exception { + return null; + } + }) + .to(TestHelper.testConsumer()) + .assertNoValues() + .assertError(NullPointerException.class) + .assertErrorMessage("The mapper returned a null MaybeSource"); + } + + @Test + public void concatMapMaybeValueErrorThrown() { + Single.just(1).concatMapMaybe(new Function>() { + @Override public MaybeSource apply(final Integer integer) throws Exception { + throw new RuntimeException("something went terribly wrong!"); + } + }) + .to(TestHelper.testConsumer()) + .assertNoValues() + .assertError(RuntimeException.class) + .assertErrorMessage("something went terribly wrong!"); + } + + @Test + public void concatMapMaybeError() { + RuntimeException exception = new RuntimeException("test"); + + Single.error(exception).concatMapMaybe(new Function>() { + @Override public MaybeSource apply(final Object integer) throws Exception { + return Maybe.just(new Object()); + } + }) + .test() + .assertError(exception); + } + + @Test + public void dispose() { + TestHelper.checkDisposed(Single.just(1).concatMapMaybe(new Function>() { + @Override + public MaybeSource apply(Integer v) throws Exception { + return Maybe.just(1); + } + })); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeSingleToMaybe(new Function, MaybeSource>() { + @Override + public MaybeSource apply(Single v) throws Exception { + return v.concatMapMaybe(new Function>() { + @Override + public MaybeSource apply(Integer v) throws Exception { + return Maybe.just(1); + } + }); + } + }); + } + + @Test + public void mapsToError() { + Single.just(1).concatMapMaybe(new Function>() { + @Override + public MaybeSource apply(Integer v) throws Exception { + return Maybe.error(new TestException()); + } + }) + .test() + .assertFailure(TestException.class); + } + + @Test + public void mapsToEmpty() { + Single.just(1).concatMapMaybe(new Function>() { + @Override + public MaybeSource apply(Integer v) throws Exception { + return Maybe.empty(); + } + }) + .test() + .assertResult(); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatMapTest.java new file mode 100644 index 00000000000..1fa2ebaf0b4 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatMapTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class SingleConcatMapTest extends RxJavaTest { + + @Test + public void concatMapValue() { + Single.just(1).concatMap(new Function>() { + @Override public SingleSource apply(final Integer integer) throws Exception { + if (integer == 1) { + return Single.just(2); + } + + return Single.just(1); + } + }) + .test() + .assertResult(2); + } + + @Test + public void concatMapValueDifferentType() { + Single.just(1).concatMap(new Function>() { + @Override public SingleSource apply(final Integer integer) throws Exception { + if (integer == 1) { + return Single.just("2"); + } + + return Single.just("1"); + } + }) + .test() + .assertResult("2"); + } + + @Test + public void concatMapValueNull() { + Single.just(1).concatMap(new Function>() { + @Override public SingleSource apply(final Integer integer) throws Exception { + return null; + } + }) + .to(TestHelper.testConsumer()) + .assertNoValues() + .assertError(NullPointerException.class) + .assertErrorMessage("The single returned by the mapper is null"); + } + + @Test + public void concatMapValueErrorThrown() { + Single.just(1).concatMap(new Function>() { + @Override public SingleSource apply(final Integer integer) throws Exception { + throw new RuntimeException("something went terribly wrong!"); + } + }) + .to(TestHelper.testConsumer()) + .assertNoValues() + .assertError(RuntimeException.class) + .assertErrorMessage("something went terribly wrong!"); + } + + @Test + public void concatMapError() { + RuntimeException exception = new RuntimeException("test"); + + Single.error(exception).concatMap(new Function>() { + @Override public SingleSource apply(final Object integer) throws Exception { + return Single.just(new Object()); + } + }) + .test() + .assertError(exception); + } + + @Test + public void dispose() { + TestHelper.checkDisposed(Single.just(1).concatMap(new Function>() { + @Override + public SingleSource apply(Integer v) throws Exception { + return Single.just(2); + } + })); + } + + @Test + public void mappedSingleOnError() { + Single.just(1).concatMap(new Function>() { + @Override + public SingleSource apply(Integer v) throws Exception { + return Single.error(new TestException()); + } + }) + .test() + .assertFailure(TestException.class); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeSingle(new Function, SingleSource>() { + @Override + public SingleSource apply(Single s) + throws Exception { + return s.concatMap(new Function>() { + @Override + public SingleSource apply(Object v) + throws Exception { + return Single.just(v); + } + }); + } + }); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatPublisherTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatPublisherTest.java index bd31e284308..883903e1d9c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatPublisherTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatPublisherTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.operators.single; import java.util.concurrent.Callable; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatTest.java index bf8c534f46c..fb94277e43a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleConcatTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleContainstTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleContainstTest.java index 4a991c4cbf2..2f5baa4ed0a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleContainstTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleContainstTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleCreateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleCreateTest.java index 489744b7087..862757560a6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleCreateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleCreateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -25,16 +25,12 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Cancellable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class SingleCreateTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void nullArgument() { - Single.create(null); - } - @Test + @SuppressUndeliverable public void basic() { final Disposable d = Disposable.empty(); @@ -56,6 +52,7 @@ public void subscribe(SingleEmitter e) throws Exception { } @Test + @SuppressUndeliverable public void basicWithCancellable() { final Disposable d1 = Disposable.empty(); final Disposable d2 = Disposable.empty(); @@ -85,6 +82,7 @@ public void cancel() throws Exception { } @Test + @SuppressUndeliverable public void basicWithError() { final Disposable d = Disposable.empty(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDeferTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDeferTest.java index 962a3694c2b..7fed907ab48 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDeferTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDeferTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayTest.java index 555b53e30ac..bc137d16120 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDelayTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -19,18 +19,18 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; -import io.reactivex.rxjava3.disposables.Disposable; import org.junit.Test; import org.reactivestreams.Subscriber; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.*; -import io.reactivex.rxjava3.subjects.PublishSubject; +import io.reactivex.rxjava3.subjects.*; import io.reactivex.rxjava3.testsupport.TestHelper; public class SingleDelayTest extends RxJavaTest { @@ -270,4 +270,16 @@ public Single apply(Single s) throws Exception { }); } + + @Test + public void withPublisherDoubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowableToSingle( + f -> SingleSubject.create().delaySubscription(f)); + } + + @Test + public void withObservableDoubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeObservableToSingle( + o -> SingleSubject.create().delaySubscription(o)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDematerializeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDematerializeTest.java index 5bf14094980..6cd05b71284 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDematerializeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDematerializeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDetachTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDetachTest.java index ae13a0d9c04..17812c8957f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDetachTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDetachTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterSuccessTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterSuccessTest.java index 20900159509..de83cecb1a8 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterSuccessTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterSuccessTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -67,11 +67,6 @@ public void error() { assertTrue(values.isEmpty()); } - @Test(expected = NullPointerException.class) - public void consumerNull() { - Single.just(1).doAfterSuccess(null); - } - @Test public void justConditional() { Single.just(1) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterTerminateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterTerminateTest.java index b4c8c1e7ca5..6b98da8c666 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterTerminateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoAfterTerminateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -61,11 +61,6 @@ public void error() { assertAfterTerminateCalledOnce(); } - @Test(expected = NullPointerException.class) - public void afterTerminateActionNull() { - Single.just(1).doAfterTerminate(null); - } - @Test public void justConditional() { Single.just(1) diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoFinallyTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoFinallyTest.java index 22f6e45c298..64afc620ac3 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoFinallyTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoFinallyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -65,11 +65,6 @@ public Single apply(Single f) throws Exception { }); } - @Test(expected = NullPointerException.class) - public void nullAction() { - Single.just(1).doFinally(null); - } - @Test public void actionThrows() { List errors = TestHelper.trackPluginErrors(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnLifecycleTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnLifecycleTest.java new file mode 100644 index 00000000000..f14d03cc8d9 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnLifecycleTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.subjects.SingleSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class SingleDoOnLifecycleTest extends RxJavaTest { + + @Test + public void success() throws Throwable { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + Single.just(1) + .doOnLifecycle(onSubscribe, onDispose) + .test() + .assertResult(1); + + verify(onSubscribe).accept(any()); + verify(onDispose, never()).run(); + } + + @Test + public void error() throws Throwable { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + Single.error(new TestException()) + .doOnLifecycle(onSubscribe, onDispose) + .test() + .assertFailure(TestException.class); + + verify(onSubscribe).accept(any()); + verify(onDispose, never()).run(); + } + + @Test + public void onSubscribeCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + doThrow(new TestException("First")).when(onSubscribe).accept(any()); + + Disposable bs = Disposable.empty(); + + new Single() { + @Override + protected void subscribeActual(SingleObserver observer) { + observer.onSubscribe(bs); + observer.onError(new TestException("Second")); + observer.onSuccess(1); + } + } + .doOnLifecycle(onSubscribe, onDispose) + .to(TestHelper.testConsumer()) + .assertFailureAndMessage(TestException.class, "First"); + + assertTrue(bs.isDisposed()); + + TestHelper.assertUndeliverable(errors, 0, TestException.class, "Second"); + + verify(onSubscribe).accept(any()); + verify(onDispose, never()).run(); + }); + } + + @Test + public void onDisposeCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + doThrow(new TestException("First")).when(onDispose).run(); + + SingleSubject ss = SingleSubject.create(); + + TestObserver to = ss + .doOnLifecycle(onSubscribe, onDispose) + .test(); + + assertTrue(ss.hasObservers()); + + to.dispose(); + + assertFalse(ss.hasObservers()); + + TestHelper.assertUndeliverable(errors, 0, TestException.class, "First"); + + verify(onSubscribe).accept(any()); + verify(onDispose).run(); + }); + } + + @Test + public void dispose() throws Throwable { + @SuppressWarnings("unchecked") + Consumer onSubscribe = mock(Consumer.class); + Action onDispose = mock(Action.class); + + SingleSubject ss = SingleSubject.create(); + + TestObserver to = ss + .doOnLifecycle(onSubscribe, onDispose) + .test(); + + assertTrue(ss.hasObservers()); + + to.dispose(); + + assertFalse(ss.hasObservers()); + + verify(onSubscribe).accept(any()); + verify(onDispose).run(); + } + + @Test + public void isDisposed() { + TestHelper.checkDisposed(SingleSubject.create().doOnLifecycle(d -> { }, () -> { })); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeSingle(m -> m.doOnLifecycle(d -> { }, () -> { })); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnTerminateTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnTerminateTest.java index 58ba686e810..814a38bded9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnTerminateTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnTerminateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,11 +27,6 @@ public class SingleDoOnTerminateTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void doOnTerminate() { - Single.just(1).doOnTerminate(null); - } - @Test public void doOnTerminateSuccess() { final AtomicBoolean atomicBoolean = new AtomicBoolean(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnTest.java index cf672026414..92ce91b65ab 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleDoOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleEqualsTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleEqualsTest.java index c6647848699..95262992310 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleEqualsTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleEqualsTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,11 +24,39 @@ public class SingleEqualsTest extends RxJavaTest { + @Test + public void bothSucceedEqual() { + Single.sequenceEqual(Single.just(1), Single.just(1)) + .test() + .assertResult(true); + } + + @Test + public void bothSucceedNotEqual() { + Single.sequenceEqual(Single.just(1), Single.just(2)) + .test() + .assertResult(false); + } + + @Test + public void firstSucceedOtherError() { + Single.sequenceEqual(Single.just(1), Single.error(new TestException())) + .test() + .assertFailure(TestException.class); + } + + @Test + public void firstErrorOtherSucceed() { + Single.sequenceEqual(Single.error(new TestException()), Single.just(1)) + .test() + .assertFailure(TestException.class); + } + @Test public void bothError() { List errors = TestHelper.trackPluginErrors(); try { - Single.equals(Single.error(new TestException("One")), Single.error(new TestException("Two"))) + Single.sequenceEqual(Single.error(new TestException("One")), Single.error(new TestException("Two"))) .to(TestHelper.testConsumer()) .assertFailureAndMessage(TestException.class, "One"); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleErrorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleErrorTest.java index b3619b59923..835ad2ad09c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleErrorTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleErrorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapBiSelectorTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapBiSelectorTest.java new file mode 100644 index 00000000000..78705fe166c --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapBiSelectorTest.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.subjects.SingleSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class SingleFlatMapBiSelectorTest extends RxJavaTest { + + BiFunction stringCombine() { + return new BiFunction() { + @Override + public String apply(Integer a, Integer b) throws Exception { + return a + ":" + b; + } + }; + } + + @Test + public void normal() { + Single.just(1) + .flatMap(new Function>() { + @Override + public SingleSource apply(Integer v) throws Exception { + return Single.just(2); + } + }, stringCombine()) + .test() + .assertResult("1:2"); + } + + @Test + public void errorWithJust() { + final int[] call = { 0 }; + + Single.error(new TestException()) + .flatMap(new Function>() { + @Override + public SingleSource apply(Integer v) throws Exception { + call[0]++; + return Single.just(1); + } + }, stringCombine()) + .test() + .assertFailure(TestException.class); + + assertEquals(0, call[0]); + } + + @Test + public void justWithError() { + final int[] call = { 0 }; + + Single.just(1) + .flatMap(new Function>() { + @Override + public SingleSource apply(Integer v) throws Exception { + call[0]++; + return Single.error(new TestException()); + } + }, stringCombine()) + .test() + .assertFailure(TestException.class); + + assertEquals(1, call[0]); + } + + @Test + public void dispose() { + TestHelper.checkDisposed(SingleSubject.create() + .flatMap(new Function>() { + @Override + public SingleSource apply(Object v) throws Exception { + return Single.just(1); + } + }, new BiFunction() { + @Override + public Object apply(Object a, Integer b) throws Exception { + return b; + } + })); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeSingle(new Function, SingleSource>() { + @Override + public SingleSource apply(Single v) throws Exception { + return v.flatMap(new Function>() { + @Override + public SingleSource apply(Object v) throws Exception { + return Single.just(1); + } + }, new BiFunction() { + @Override + public Object apply(Object a, Integer b) throws Exception { + return b; + } + }); + } + }); + } + + @Test + public void mapperThrows() { + Single.just(1) + .flatMap(new Function>() { + @Override + public SingleSource apply(Integer v) throws Exception { + throw new TestException(); + } + }, stringCombine()) + .test() + .assertFailure(TestException.class); + } + + @Test + public void mapperReturnsNull() { + Single.just(1) + .flatMap(new Function>() { + @Override + public SingleSource apply(Integer v) throws Exception { + return null; + } + }, stringCombine()) + .test() + .assertFailure(NullPointerException.class); + } + + @Test + public void resultSelectorThrows() { + Single.just(1) + .flatMap(new Function>() { + @Override + public SingleSource apply(Integer v) throws Exception { + return Single.just(2); + } + }, new BiFunction() { + @Override + public Object apply(Integer a, Integer b) throws Exception { + throw new TestException(); + } + }) + .test() + .assertFailure(TestException.class); + } + + @Test + public void resultSelectorReturnsNull() { + Single.just(1) + .flatMap(new Function>() { + @Override + public SingleSource apply(Integer v) throws Exception { + return Single.just(2); + } + }, new BiFunction() { + @Override + public Object apply(Integer a, Integer b) throws Exception { + return null; + } + }) + .test() + .assertFailure(NullPointerException.class); + } + + @Test + public void mapperCancels() { + final TestObserver to = new TestObserver<>(); + + Single.just(1) + .flatMap(new Function>() { + @Override + public SingleSource apply(Integer v) throws Exception { + to.dispose(); + return Single.just(2); + } + }, new BiFunction() { + @Override + public Integer apply(Integer a, Integer b) throws Exception { + throw new IllegalStateException(); + } + }) + .subscribeWith(to) + .assertEmpty(); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapCompletableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapCompletableTest.java index 6e663394e5c..c4af049aec9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapCompletableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableFlowableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableFlowableTest.java index 4643d613038..277b9aa13b9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableFlowableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableFlowableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,13 +21,15 @@ import org.junit.Test; import org.reactivestreams.Subscription; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.util.CrashingIterable; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; import io.reactivex.rxjava3.schedulers.Schedulers; -import io.reactivex.rxjava3.subjects.PublishSubject; +import io.reactivex.rxjava3.subjects.*; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; @@ -585,4 +587,51 @@ public void run() { TestHelper.race(r1, r2); } } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeSingleToFlowable(s -> s.flattenAsFlowable(v -> Collections.emptyList())); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(SingleSubject.create().flattenAsFlowable(v -> Collections.emptyList())); + } + + @Test + public void slowPatchCancelAfterOnNext() { + TestSubscriber ts = new TestSubscriber() { + @Override + public void onNext(@NonNull Integer t) { + super.onNext(t); + cancel(); + onComplete(); + } + }; + + Single.just(1) + .flattenAsFlowable(v -> Arrays.asList(1, 2)) + .subscribe(ts); + + ts.assertResult(1); + } + + @Test + public void onSuccessRequestRace() { + List list = Arrays.asList(1); + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + + SingleSubject ss = SingleSubject.create(); + + TestSubscriber ts = ss.flattenAsFlowable(v -> list) + .test(0L); + + TestHelper.race( + () -> ss.onSuccess(1), + () -> ts.request(1) + ); + + ts.assertResult(1); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableObservableTest.java index 5d2bafc9c98..82448746b83 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapIterableObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -25,8 +25,9 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Function; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.util.CrashingIterable; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.testsupport.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapMaybeTest.java index b98bf5537f5..6081a621e88 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapMaybeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapMaybeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,12 +21,6 @@ import io.reactivex.rxjava3.testsupport.TestHelper; public class SingleFlatMapMaybeTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void flatMapMaybeNull() { - Single.just(1) - .flatMapMaybe(null); - } - @Test public void flatMapMaybeValue() { Single.just(1).flatMapMaybe(new Function>() { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapNotificationTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapNotificationTest.java new file mode 100644 index 00000000000..00f1337b2cc --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapNotificationTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.List; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.testsupport.*; + +public class SingleFlatMapNotificationTest extends RxJavaTest { + + @Test + public void dispose() { + TestHelper.checkDisposed(Single.just(1) + .flatMap(Functions.justFunction(Single.just(1)), + Functions.justFunction(Single.just(1)))); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeSingle(new Function, SingleSource>() { + @Override + public SingleSource apply(Single m) throws Exception { + return m + .flatMap(Functions.justFunction(Single.just(1)), + Functions.justFunction(Single.just(1))); + } + }); + } + + @Test + public void onSuccessNull() { + Single.just(1) + .flatMap(Functions.justFunction((Single)null), + Functions.justFunction(Single.just(1))) + .test() + .assertFailure(NullPointerException.class); + } + + @Test + public void onErrorNull() { + TestObserverEx to = Single.error(new TestException()) + .flatMap(Functions.justFunction(Single.just(1)), + Functions.justFunction((Single)null)) + .to(TestHelper.testConsumer()) + .assertFailure(CompositeException.class); + + List ce = TestHelper.compositeList(to.errors().get(0)); + + TestHelper.assertError(ce, 0, TestException.class); + TestHelper.assertError(ce, 1, NullPointerException.class); + } + + @Test + public void onSuccessError() { + Single.just(1) + .flatMap(Functions.justFunction(Single.error(new TestException())), + Functions.justFunction((Single)null)) + .test() + .assertFailure(TestException.class); + } + + @Test + public void onSucccessSuccess() { + Single.just(1) + .flatMap(v -> Single.just(2), e -> Single.just(3)) + .test() + .assertResult(2); + } + + @Test + public void onErrorSuccess() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Single.error(new TestException()) + .flatMap(v -> Single.just(2), e -> Single.just(3)) + .test() + .assertResult(3); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void onErrorError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Single.error(new TestException()) + .flatMap(v -> Single.just(2), e -> Single.error(new IOException())) + .test() + .assertFailure(IOException.class); + + assertTrue("" + errors, errors.isEmpty()); + }); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapTest.java index 1845a4967d8..08d3d24c5a0 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFlatMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -129,11 +129,6 @@ public Publisher apply(Integer v) throws Exception { .assertResult(1, 2, 3, 4, 5); } - @Test(expected = NullPointerException.class) - public void flatMapPublisherMapperNull() { - Single.just(1).flatMapPublisher(null); - } - @Test public void flatMapPublisherMapperThrows() { final TestException ex = new TestException(); @@ -215,12 +210,6 @@ public void run() throws Exception { ts.assertNotTerminated(); } - @Test(expected = NullPointerException.class) - public void flatMapNull() { - Single.just(1) - .flatMap(null); - } - @Test public void flatMapValue() { Single.just(1).flatMap(new Function>() { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromCallableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromCallableTest.java index 8a97b8a2d6f..33520299899 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromCallableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromCallableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromMaybeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromMaybeTest.java new file mode 100644 index 00000000000..293cedf574c --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromMaybeTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import static org.junit.Assert.*; + +import java.util.NoSuchElementException; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.subjects.MaybeSubject; + +public class SingleFromMaybeTest extends RxJavaTest { + + @Test + public void success() { + Single.fromMaybe(Maybe.just(1).hide()) + .test() + .assertResult(1); + } + + @Test + public void empty() { + Single.fromMaybe(Maybe.empty().hide()) + .test() + .assertFailure(NoSuchElementException.class); + } + + @Test + public void emptyDefault() { + Single.fromMaybe(Maybe.empty().hide(), 1) + .test() + .assertResult(1); + } + + @Test + public void error() { + Single.fromMaybe(Maybe.error(new TestException()).hide()) + .test() + .assertFailure(TestException.class); + } + + @Test + public void cancelComposes() { + MaybeSubject ms = MaybeSubject.create(); + + TestObserver to = Single.fromMaybe(ms) + .test(); + + to.assertEmpty(); + + assertTrue(ms.hasObservers()); + + to.dispose(); + + assertFalse(ms.hasObservers()); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromPublisherTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromPublisherTest.java index 74261bc7ddd..080870b228c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromPublisherTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromPublisherTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromSupplierTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromSupplierTest.java index dd259f209b0..927ec7f8378 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromSupplierTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromSupplierTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromTest.java index 46847bedd32..a322d8852e7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleFromTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,7 +24,8 @@ public class SingleFromTest extends RxJavaTest { @Test public void fromFuture() throws Exception { - Single.fromFuture(Flowable.just(1).toFuture(), Schedulers.io()) + Single.fromFuture(Flowable.just(1).toFuture()) + .subscribeOn(Schedulers.io()) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1); @@ -32,7 +33,8 @@ public void fromFuture() throws Exception { @Test public void fromFutureTimeout() throws Exception { - Single.fromFuture(Flowable.never().toFuture(), 1, TimeUnit.SECONDS, Schedulers.io()) + Single.fromFuture(Flowable.never().toFuture(), 1, TimeUnit.SECONDS) + .subscribeOn(Schedulers.io()) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(TimeoutException.class); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleHideTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleHideTest.java index 9c5609b571e..d13218bc84a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleHideTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleHideTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleInternalHelperTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleInternalHelperTest.java index e551b882d1f..478a03d9ff6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleInternalHelperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleInternalHelperTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -31,8 +31,8 @@ public void utilityClass() { @Test public void noSuchElementCallableEnum() { - assertEquals(1, SingleInternalHelper.NoSuchElementCallable.values().length); - assertNotNull(SingleInternalHelper.NoSuchElementCallable.valueOf("INSTANCE")); + assertEquals(1, SingleInternalHelper.NoSuchElementSupplier.values().length); + assertNotNull(SingleInternalHelper.NoSuchElementSupplier.valueOf("INSTANCE")); } @Test @@ -41,12 +41,6 @@ public void toFlowableEnum() { assertNotNull(SingleInternalHelper.ToFlowable.valueOf("INSTANCE")); } - @Test - public void toObservableEnum() { - assertEquals(1, SingleInternalHelper.ToObservable.values().length); - assertNotNull(SingleInternalHelper.ToObservable.valueOf("INSTANCE")); - } - @Test public void singleIterableToFlowableIterable() { Iterable> it = SingleInternalHelper.iterableToFlowable( diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleLiftTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleLiftTest.java index 1638cb993fd..6fdd626bd3b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleLiftTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleLiftTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMapTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMapTest.java index 1ae83e91587..eb220e0580b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,11 +21,6 @@ public class SingleMapTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void mapNull() { - Single.just(1).map(null); - } - @Test public void mapValue() { Single.just(1).map(new Function() { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMaterializeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMaterializeTest.java index 4bc05ea67d5..46625b80ab4 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMaterializeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMaterializeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMergeArrayTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMergeArrayTest.java new file mode 100644 index 00000000000..b2bda3a7d79 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMergeArrayTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; + +public class SingleMergeArrayTest extends RxJavaTest { + + @Test + public void normal() { + Single.mergeArray(Single.just(1), Single.just(2), Single.just(3)) + .test() + .assertResult(1, 2, 3); + } + + @Test + public void error() { + Single.mergeArray(Single.just(1), Single.error(new TestException()), Single.just(3)) + .test() + .assertFailure(TestException.class, 1); + } + + @Test + public void normalDelayError() { + Single.mergeArrayDelayError(Single.just(1), Single.just(2), Single.just(3)) + .test() + .assertResult(1, 2, 3); + } + + @Test + public void errorDelayError() { + Single.mergeArrayDelayError(Single.just(1), Single.error(new TestException()), Single.just(3)) + .test() + .assertFailure(TestException.class, 1, 3); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMergeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMergeTest.java index 7aba476c86e..dd4844da5b0 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMergeTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMergeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMiscTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMiscTest.java index ca2ccacdc2f..93eebfe7ec6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMiscTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleMiscTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -280,11 +280,11 @@ public void toObservable() { @Test public void equals() { - Single.equals(Single.just(1), Single.just(1).hide()) + Single.sequenceEqual(Single.just(1), Single.just(1).hide()) .test() .assertResult(true); - Single.equals(Single.just(1), Single.just(2)) + Single.sequenceEqual(Single.just(1), Single.just(2)) .test() .assertResult(false); } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleObserveOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleObserveOnTest.java index afb4494befe..4abc87e51f8 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleObserveOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleObserveOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleOfTypeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleOfTypeTest.java new file mode 100644 index 00000000000..9569e9a35dc --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleOfTypeTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class SingleOfTypeTest extends RxJavaTest { + + @Test + public void normal() { + Single.just(1).ofType(Integer.class) + .test() + .assertResult(1); + } + + @Test + public void normalDowncast() { + TestObserver to = Single.just(1) + .ofType(Number.class) + .test(); + // don't make this fluent, target type required! + to.assertResult((Number)1); + } + + @Test + public void notInstance() { + TestObserver to = Single.just(1) + .ofType(String.class) + .test(); + // don't make this fluent, target type required! + to.assertResult(); + } + + @Test + public void error() { + TestObserver to = Single.error(new TestException()) + .ofType(Number.class) + .test(); + // don't make this fluent, target type required! + to.assertFailure(TestException.class); + } + + @Test + public void errorNotInstance() { + TestObserver to = Single.error(new TestException()) + .ofType(String.class) + .test(); + // don't make this fluent, target type required! + to.assertFailure(TestException.class); + } + + @Test + public void dispose() { + TestHelper.checkDisposedSingleToMaybe(new Function, Maybe>() { + @Override + public Maybe apply(Single m) throws Exception { + return m.ofType(Object.class); + } + }); + } + + @Test + public void isDisposed() { + PublishProcessor pp = PublishProcessor.create(); + + TestHelper.checkDisposed(pp.singleElement().ofType(Object.class)); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeSingleToMaybe(new Function, Maybe>() { + @Override + public Maybe apply(Single f) throws Exception { + return f.ofType(Object.class); + } + }); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorCompleteTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorCompleteTest.java new file mode 100644 index 00000000000..9b184ae7f8d --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorCompleteTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Single; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.subjects.*; +import io.reactivex.rxjava3.testsupport.*; + +public class SingleOnErrorCompleteTest { + + @Test + public void normal() { + Single.just(1) + .onErrorComplete() + .test() + .assertResult(1); + } + + @Test + public void error() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Single.error(new TestException()) + .onErrorComplete() + .test() + .assertResult(); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void errorMatches() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Single.error(new TestException()) + .onErrorComplete(error -> error instanceof TestException) + .test() + .assertResult(); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void errorNotMatches() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Single.error(new IOException()) + .onErrorComplete(error -> error instanceof TestException) + .test() + .assertFailure(IOException.class); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void errorPredicateCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + TestObserverEx to = Single.error(new IOException()) + .onErrorComplete(error -> { throw new TestException(); }) + .subscribeWith(new TestObserverEx<>()) + .assertFailure(CompositeException.class); + + TestHelper.assertError(to, 0, IOException.class); + TestHelper.assertError(to, 1, TestException.class); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void dispose() { + SingleSubject ss = SingleSubject.create(); + + TestObserver to = ss + .onErrorComplete() + .test(); + + assertTrue("No subscribers?!", ss.hasObservers()); + + to.dispose(); + + assertFalse("Still subscribers?!", ss.hasObservers()); + } + + @Test + public void onSubscribe() { + TestHelper.checkDoubleOnSubscribeSingleToMaybe(f -> f.onErrorComplete()); + } + + @Test + public void isDisposed() { + TestHelper.checkDisposed(SingleSubject.create().onErrorComplete()); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorXTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorXTest.java index 990a0fdec67..42e36eaba86 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorXTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleOnErrorXTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleSafeSubscribeTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleSafeSubscribeTest.java new file mode 100644 index 00000000000..d9711c67c01 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleSafeSubscribeTest.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import java.io.IOException; + +import org.junit.Test; +import org.mockito.InOrder; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class SingleSafeSubscribeTest { + + @Test + public void normalSuccess() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + SingleObserver consumer = mock(SingleObserver.class); + + Single.just(1) + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onSuccess(1); + order.verifyNoMoreInteractions(); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void normalError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + SingleObserver consumer = mock(SingleObserver.class); + + Single.error(new TestException()) + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onError(any(TestException.class)); + order.verifyNoMoreInteractions(); + + assertTrue("" + errors, errors.isEmpty()); + }); + } + + @Test + public void onSubscribeCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + SingleObserver consumer = mock(SingleObserver.class); + doThrow(new TestException()).when(consumer).onSubscribe(any()); + + Disposable d = Disposable.empty(); + + new Single() { + @Override + protected void subscribeActual(@NonNull SingleObserver observer) { + observer.onSubscribe(d); + // none of the following should arrive at the consumer + observer.onSuccess(1); + observer.onError(new IOException()); + } + } + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verifyNoMoreInteractions(); + + assertTrue(d.isDisposed()); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + TestHelper.assertUndeliverable(errors, 1, IOException.class); + }); + } + + @Test + public void onSuccessCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + SingleObserver consumer = mock(SingleObserver.class); + doThrow(new TestException()).when(consumer).onSuccess(any()); + + new Single() { + @Override + protected void subscribeActual(@NonNull SingleObserver observer) { + observer.onSubscribe(Disposable.empty()); + observer.onSuccess(1); + } + } + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onSuccess(1); + order.verifyNoMoreInteractions(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } + + @Test + public void onErrorCrash() throws Throwable { + TestHelper.withErrorTracking(errors -> { + @SuppressWarnings("unchecked") + SingleObserver consumer = mock(SingleObserver.class); + doThrow(new TestException()).when(consumer).onError(any()); + + new Single() { + @Override + protected void subscribeActual(@NonNull SingleObserver observer) { + observer.onSubscribe(Disposable.empty()); + // none of the following should arrive at the consumer + observer.onError(new IOException()); + } + } + .safeSubscribe(consumer); + + InOrder order = inOrder(consumer); + order.verify(consumer).onSubscribe(any(Disposable.class)); + order.verify(consumer).onError(any(IOException.class)); + order.verifyNoMoreInteractions(); + + TestHelper.assertError(errors, 0, CompositeException.class); + + CompositeException compositeException = (CompositeException)errors.get(0); + TestHelper.assertError(compositeException.getExceptions(), 0, IOException.class); + TestHelper.assertError(compositeException.getExceptions(), 1, TestException.class); + }); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleStartWithTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleStartWithTest.java new file mode 100644 index 00000000000..3d01226d9aa --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleStartWithTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; + +public class SingleStartWithTest { + + @Test + public void justCompletableComplete() { + Single.just(1) + .startWith(Completable.complete()) + .test() + .assertResult(1); + } + + @Test + public void justCompletableError() { + Single.just(1) + .startWith(Completable.error(new TestException())) + .test() + .assertFailure(TestException.class); + } + + @Test + public void justSingleJust() { + Single.just(1) + .startWith(Single.just(0)) + .test() + .assertResult(0, 1); + } + + @Test + public void justSingleError() { + Single.just(1) + .startWith(Single.error(new TestException())) + .test() + .assertFailure(TestException.class); + } + + @Test + public void justMaybeJust() { + Single.just(1) + .startWith(Maybe.just(0)) + .test() + .assertResult(0, 1); + } + + @Test + public void justMaybeEmpty() { + Single.just(1) + .startWith(Maybe.empty()) + .test() + .assertResult(1); + } + + @Test + public void justMaybeError() { + Single.just(1) + .startWith(Maybe.error(new TestException())) + .test() + .assertFailure(TestException.class); + } + + @Test + public void justObservableJust() { + Single.just(1) + .startWith(Observable.just(-1, 0)) + .test() + .assertResult(-1, 0, 1); + } + + @Test + public void justObservableEmpty() { + Single.just(1) + .startWith(Observable.empty()) + .test() + .assertResult(1); + } + + @Test + public void justObservableError() { + Single.just(1) + .startWith(Observable.error(new TestException())) + .test() + .assertFailure(TestException.class); + } + + @Test + public void justFlowableJust() { + Single.just(1) + .startWith(Flowable.just(-1, 0)) + .test() + .assertResult(-1, 0, 1); + } + + @Test + public void justFlowableEmpty() { + Single.just(1) + .startWith(Observable.empty()) + .test() + .assertResult(1); + } + + @Test + public void justFlowableError() { + Single.just(1) + .startWith(Flowable.error(new TestException())) + .test() + .assertFailure(TestException.class); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleSubscribeOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleSubscribeOnTest.java index 0c22190691d..bec9782b0ef 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleSubscribeOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleSubscribeOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleSwitchOnNextTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleSwitchOnNextTest.java new file mode 100644 index 00000000000..f3c119222d8 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleSwitchOnNextTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.subjects.SingleSubject; +import io.reactivex.rxjava3.subscribers.TestSubscriber; + +public class SingleSwitchOnNextTest extends RxJavaTest { + + @Test + public void normal() { + Single.switchOnNext( + Flowable.range(1, 5) + .map(v -> { + if (v % 2 == 0) { + return Single.just(v); + } + return Single.just(10 + v); + }) + ) + .test() + .assertResult(11, 2, 13, 4, 15); + } + + @Test + public void normalDelayError() { + Single.switchOnNextDelayError( + Flowable.range(1, 5) + .map(v -> { + if (v % 2 == 0) { + return Single.just(v); + } + return Single.just(10 + v); + }) + ) + .test() + .assertResult(11, 2, 13, 4, 15); + } + + @Test + public void noDelaySwitch() { + PublishProcessor> pp = PublishProcessor.create(); + + TestSubscriber ts = Single.switchOnNext(pp).test(); + + assertTrue(pp.hasSubscribers()); + + ts.assertEmpty(); + + SingleSubject ss1 = SingleSubject.create(); + SingleSubject ss2 = SingleSubject.create(); + + pp.onNext(ss1); + + assertTrue(ss1.hasObservers()); + + pp.onNext(ss2); + + assertFalse(ss1.hasObservers()); + assertTrue(ss2.hasObservers()); + + pp.onComplete(); + + assertTrue(ss2.hasObservers()); + + ss2.onSuccess(1); + + ts.assertResult(1); + } + + @Test + public void delaySwitch() { + PublishProcessor> pp = PublishProcessor.create(); + + TestSubscriber ts = Single.switchOnNextDelayError(pp).test(); + + assertTrue(pp.hasSubscribers()); + + ts.assertEmpty(); + + SingleSubject ss1 = SingleSubject.create(); + SingleSubject ss2 = SingleSubject.create(); + + pp.onNext(ss1); + + assertTrue(ss1.hasObservers()); + + pp.onNext(ss2); + + assertFalse(ss1.hasObservers()); + assertTrue(ss2.hasObservers()); + + assertTrue(ss2.hasObservers()); + + ss2.onError(new TestException()); + + assertTrue(pp.hasSubscribers()); + + ts.assertEmpty(); + + pp.onComplete(); + + ts.assertFailure(TestException.class); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTakeUntilTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTakeUntilTest.java index 0a2d27340ac..c5389b0bbd0 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTakeUntilTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTakeUntilTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeIntervalTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeIntervalTest.java new file mode 100644 index 00000000000..ade198db50f --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeIntervalTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Single; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.schedulers.*; +import io.reactivex.rxjava3.subjects.SingleSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class SingleTimeIntervalTest { + + @Test + public void just() { + Single.just(1) + .timestamp() + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void error() { + Single.error(new TestException()) + .timestamp() + .test() + .assertFailure(TestException.class); + } + + @Test + public void justSeconds() { + Single.just(1) + .timestamp(TimeUnit.SECONDS) + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void justScheduler() { + Single.just(1) + .timestamp(Schedulers.single()) + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void justSecondsScheduler() { + Single.just(1) + .timestamp(TimeUnit.SECONDS, Schedulers.single()) + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeSingle(m -> m.timestamp()); + } + + @Test + public void dispose() { + TestHelper.checkDisposed(SingleSubject.create().timestamp()); + } + + @Test + public void timeInfo() { + TestScheduler scheduler = new TestScheduler(); + + SingleSubject ss = SingleSubject.create(); + + TestObserver> to = ss + .timestamp(scheduler) + .test(); + + scheduler.advanceTimeBy(1000, TimeUnit.MILLISECONDS); + + ss.onSuccess(1); + + to.assertResult(new Timed<>(1, 1000L, TimeUnit.MILLISECONDS)); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeoutTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeoutTest.java index 7c51e8be913..e54fc112077 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeoutTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimeoutTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,12 +21,14 @@ import org.junit.Test; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Action; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.schedulers.TestScheduler; +import io.reactivex.rxjava3.schedulers.*; import io.reactivex.rxjava3.subjects.*; import io.reactivex.rxjava3.testsupport.TestHelper; @@ -216,9 +218,61 @@ public void run() { public void mainTimedOut() { Single .never() - .timeout(1, TimeUnit.NANOSECONDS) + .timeout(1, TimeUnit.MILLISECONDS) .to(TestHelper.testConsumer()) .awaitDone(5, TimeUnit.SECONDS) - .assertFailureAndMessage(TimeoutException.class, timeoutMessage(1, TimeUnit.NANOSECONDS)); + .assertFailureAndMessage(TimeoutException.class, timeoutMessage(1, TimeUnit.MILLISECONDS)); + } + + @Test + public void mainTimeoutFallbackSuccess() { + Single.never() + .timeout(1, TimeUnit.MILLISECONDS, Single.just(1)) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertResult(1); + } + + @Test + public void timeoutBeforeOnSubscribeFromMain() { + Disposable d = Disposable.empty(); + + new Single() { + @Override + protected void subscribeActual(@NonNull SingleObserver observer) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + observer.onSubscribe(d); + } + } + .timeout(1, TimeUnit.MILLISECONDS, Single.just(1)) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertResult(1); + + assertTrue(d.isDisposed()); + } + + @Test + public void timeoutWithZero() throws InterruptedException { + int n = 10_000; + Scheduler sch = Schedulers.single(); + for (int i = 0; i < n; i++) { + final int y = i; + final CountDownLatch latch = new CountDownLatch(1); + Disposable d = Single.never() + .timeout(0, TimeUnit.NANOSECONDS, sch) + .subscribe(v -> {}, e -> { + //System.out.println("timeout " + y); + latch.countDown(); + }); + if (!latch.await(2, TimeUnit.SECONDS)) { + System.out.println(d + " " + sch); + throw new IllegalStateException("Timeout did not work at y = " + y); + } + } } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimerTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimerTest.java index 2924364459e..3b5797f498d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimerTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -37,7 +37,7 @@ public void disposed() { public void timerInterruptible() throws Exception { ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); try { - for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec) }) { + for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec, true) }) { final AtomicBoolean interrupted = new AtomicBoolean(); TestObserver to = Single.timer(1, TimeUnit.MILLISECONDS, s) .map(new Function() { diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimestampTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimestampTest.java new file mode 100644 index 00000000000..206da8f428a --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleTimestampTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.operators.single; + +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.Single; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.schedulers.*; +import io.reactivex.rxjava3.subjects.SingleSubject; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class SingleTimestampTest { + + @Test + public void just() { + Single.just(1) + .timeInterval() + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void error() { + Single.error(new TestException()) + .timeInterval() + .test() + .assertFailure(TestException.class); + } + + @Test + public void justSeconds() { + Single.just(1) + .timeInterval(TimeUnit.SECONDS) + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void justScheduler() { + Single.just(1) + .timeInterval(Schedulers.single()) + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void justSecondsScheduler() { + Single.just(1) + .timeInterval(TimeUnit.SECONDS, Schedulers.single()) + .test() + .assertValueCount(1) + .assertNoErrors() + .assertComplete(); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeSingle(m -> m.timeInterval()); + } + + @Test + public void dispose() { + TestHelper.checkDisposed(SingleSubject.create().timeInterval()); + } + + @Test + public void timeInfo() { + TestScheduler scheduler = new TestScheduler(); + + SingleSubject ss = SingleSubject.create(); + + TestObserver> to = ss + .timeInterval(scheduler) + .test(); + + scheduler.advanceTimeBy(1000, TimeUnit.MILLISECONDS); + + ss.onSuccess(1); + + to.assertResult(new Timed<>(1, 1000L, TimeUnit.MILLISECONDS)); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleToFlowableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleToFlowableTest.java index f4c344c8011..1c9cf06385d 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleToFlowableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleToFlowableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleToObservableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleToObservableTest.java index 35d38d49c74..f72bd4ac603 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleToObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleToObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleUnsubscribeOnTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleUnsubscribeOnTest.java index d28c47ad084..fa07de729c7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleUnsubscribeOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleUnsubscribeOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleUsingTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleUsingTest.java index 28f268f423c..28c6b34ef75 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleUsingTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleUsingTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -293,6 +293,7 @@ protected void subscribeActual(SingleObserver observer) { } @Test + @SuppressUndeliverable public void errorDisposeRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { final PublishProcessor pp = PublishProcessor.create(); diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleZipArrayTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleZipArrayTest.java index 50989db3ecc..df41235e38b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleZipArrayTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleZipArrayTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,16 +16,19 @@ import static org.junit.Assert.*; import java.util.*; +import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.subjects.SingleSubject; import io.reactivex.rxjava3.testsupport.TestHelper; public class SingleZipArrayTest extends RxJavaTest { @@ -193,4 +196,40 @@ public void singleSourceZipperReturnsNull() { .to(TestHelper.testConsumer()) .assertFailureAndMessage(NullPointerException.class, "The zipper returned a null value"); } + + @Test + public void singleSourceZipperReturnsNull2() { + Single.zipArray(Functions.justFunction(null), Single.just(1), Single.just(2)) + .to(TestHelper.testConsumer()) + .assertFailureAndMessage(NullPointerException.class, "The zipper returned a null value"); + } + + @Test + public void dispose2() { + TestHelper.checkDisposed(Single.zipArray(Functions.justFunction(1), SingleSubject.create(), SingleSubject.create())); + } + + @Test + public void bothSucceed() { + Single.zipArray(a -> Arrays.asList(a), Single.just(1), Single.just(2)) + .test() + .assertResult(Arrays.asList(1, 2)); + } + + @Test + public void onSuccessAfterDispose() { + AtomicReference> emitter = new AtomicReference<>(); + + TestObserver> to = Single.zipArray(Arrays::asList, + (SingleSource)o -> emitter.set(o), Single.never()) + .test(); + + emitter.get().onSubscribe(Disposable.empty()); + + to.dispose(); + + emitter.get().onSuccess(1); + + to.assertEmpty(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleZipIterableTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleZipIterableTest.java index 6fd67444791..c2293a2b890 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleZipIterableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleZipIterableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleZipTest.java b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleZipTest.java index 79380cfa5fb..14f2e682674 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleZipTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/operators/single/SingleZipTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/AbstractDirectTaskTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/AbstractDirectTaskTest.java index 85507fb7f14..cd10a10443b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/AbstractDirectTaskTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/AbstractDirectTaskTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,7 +27,7 @@ public class AbstractDirectTaskTest extends RxJavaTest { @Test public void cancelSetFuture() { - AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE) { + AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE, true) { private static final long serialVersionUID = 208585707945686116L; }; final Boolean[] interrupted = { null }; @@ -58,7 +58,7 @@ public boolean cancel(boolean mayInterruptIfRunning) { @Test public void cancelSetFutureCurrentThread() { - AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE) { + AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE, true) { private static final long serialVersionUID = 208585707945686116L; }; final Boolean[] interrupted = { null }; @@ -91,7 +91,7 @@ public boolean cancel(boolean mayInterruptIfRunning) { @Test public void setFutureCancel() { - AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE) { + AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE, true) { private static final long serialVersionUID = 208585707945686116L; }; final Boolean[] interrupted = { null }; @@ -119,7 +119,7 @@ public boolean cancel(boolean mayInterruptIfRunning) { @Test public void setFutureCancelSameThread() { - AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE) { + AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE, true) { private static final long serialVersionUID = 208585707945686116L; }; final Boolean[] interrupted = { null }; @@ -148,7 +148,7 @@ public boolean cancel(boolean mayInterruptIfRunning) { @Test public void finished() { - AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE) { + AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE, true) { private static final long serialVersionUID = 208585707945686116L; }; final Boolean[] interrupted = { null }; @@ -177,7 +177,7 @@ public boolean cancel(boolean mayInterruptIfRunning) { @Test public void finishedCancel() { - AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE) { + AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE, true) { private static final long serialVersionUID = 208585707945686116L; }; final Boolean[] interrupted = { null }; @@ -211,7 +211,7 @@ public boolean cancel(boolean mayInterruptIfRunning) { @Test public void disposeSetFutureRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { - final AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE) { + final AbstractDirectTask task = new AbstractDirectTask(Functions.EMPTY_RUNNABLE, true) { private static final long serialVersionUID = 208585707945686116L; }; @@ -241,4 +241,31 @@ public void run() { TestHelper.race(r1, r2); } } + + static class TestDirectTask extends AbstractDirectTask { + private static final long serialVersionUID = 587679821055711738L; + + TestDirectTask() { + super(Functions.EMPTY_RUNNABLE, true); + } + } + + @Test + public void toStringStates() { + TestDirectTask task = new TestDirectTask(); + + assertEquals("TestDirectTask[Waiting]", task.toString()); + + task.runner = Thread.currentThread(); + + assertEquals("TestDirectTask[Running on " + Thread.currentThread() + "]", task.toString()); + + task.dispose(); + + assertEquals("TestDirectTask[Disposed]", task.toString()); + + task.set(AbstractDirectTask.FINISHED); + + assertEquals("TestDirectTask[Finished]", task.toString()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/BooleanRunnableTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/BooleanRunnableTest.java new file mode 100644 index 00000000000..237bb233eb2 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/BooleanRunnableTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.schedulers; + +import static org.junit.Assert.fail; + +import java.util.List; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.RxJavaTest; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.internal.schedulers.ExecutorScheduler.ExecutorWorker.BooleanRunnable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class BooleanRunnableTest extends RxJavaTest { + + @Test + public void runnableThrows() { + List errors = TestHelper.trackPluginErrors(); + try { + BooleanRunnable task = new BooleanRunnable(() -> { + throw new TestException(); + }); + + try { + task.run(); + fail("Should have thrown!"); + } catch (TestException expected) { + // expected + } + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + } finally { + RxJavaPlugins.reset(); + } + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/ComputationSchedulerInternalTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/ComputationSchedulerInternalTest.java index 59ad5d1dfc4..5c8aa1a65f6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/ComputationSchedulerInternalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/ComputationSchedulerInternalTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.schedulers; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/DisposeOnCancelTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/DisposeOnCancelTest.java index 8018806a377..224e33ae7d2 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/DisposeOnCancelTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/DisposeOnCancelTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/ExecutorSchedulerDelayedRunnableTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/ExecutorSchedulerDelayedRunnableTest.java index 08e06b189ef..31c31122551 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/ExecutorSchedulerDelayedRunnableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/ExecutorSchedulerDelayedRunnableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,10 +22,12 @@ import io.reactivex.rxjava3.core.RxJavaTest; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.internal.schedulers.ExecutorScheduler.DelayedRunnable; +import io.reactivex.rxjava3.testsupport.SuppressUndeliverable; public class ExecutorSchedulerDelayedRunnableTest extends RxJavaTest { @Test(expected = TestException.class) + @SuppressUndeliverable public void delayedRunnableCrash() { DelayedRunnable dl = new DelayedRunnable(new Runnable() { @Override diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/ExecutorSchedulerInternalTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/ExecutorSchedulerInternalTest.java new file mode 100644 index 00000000000..64d4d1861cc --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/ExecutorSchedulerInternalTest.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.schedulers; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +public class ExecutorSchedulerInternalTest { + + @Test + public void helperHolder() { + assertNotNull(new ExecutorScheduler.SingleHolder()); + } + +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/ImmediateThinSchedulerTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/ImmediateThinSchedulerTest.java index cacb8fabeb8..75710644d90 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/ImmediateThinSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/ImmediateThinSchedulerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/InstantPeriodicTaskTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/InstantPeriodicTaskTest.java index 7b7299f309e..4a57e867813 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/InstantPeriodicTaskTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/InstantPeriodicTaskTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.schedulers; @@ -44,7 +41,12 @@ public void run() { } }, exec); - assertNull(task.call()); + try { + task.call(); + fail("Should have thrown!"); + } catch (TestException excepted) { + // excepted + } TestHelper.assertUndeliverable(errors, 0, TestException.class); } finally { diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/InterruptibleRunnableTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/InterruptibleRunnableTest.java new file mode 100644 index 00000000000..e040b374195 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/InterruptibleRunnableTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.schedulers; + +import static org.junit.Assert.fail; + +import java.util.List; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.RxJavaTest; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.internal.schedulers.ExecutorScheduler.ExecutorWorker.InterruptibleRunnable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class InterruptibleRunnableTest extends RxJavaTest { + + @Test + public void runnableThrows() { + List errors = TestHelper.trackPluginErrors(); + try { + InterruptibleRunnable task = new InterruptibleRunnable(() -> { + throw new TestException(); + }, null); + + try { + task.run(); + fail("Should have thrown!"); + } catch (TestException expected) { + // expected + } + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + } finally { + RxJavaPlugins.reset(); + } + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/IoScheduledReleaseTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/IoScheduledReleaseTest.java new file mode 100644 index 00000000000..e3f55b75fb4 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/IoScheduledReleaseTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.schedulers; + +import io.reactivex.rxjava3.core.Completable; +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.core.RxJavaTest; +import io.reactivex.rxjava3.schedulers.Schedulers; +import org.junit.Test; + +import java.util.concurrent.TimeUnit; + +public class IoScheduledReleaseTest extends RxJavaTest { + + /* This test will be stuck in a deadlock if IoScheduler.USE_SCHEDULED_RELEASE is not set */ + @Test + public void scheduledRelease() { + boolean savedScheduledRelease = IoScheduler.USE_SCHEDULED_RELEASE; + IoScheduler.USE_SCHEDULED_RELEASE = true; + try { + Flowable.just("item") + .observeOn(Schedulers.io()) + .firstOrError() + .map(item -> { + for (int i = 0; i < 50; i++) { + Completable.complete() + .observeOn(Schedulers.io()) + .blockingAwait(); + } + return "Done"; + }) + .ignoreElement() + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertComplete(); + } finally { + IoScheduler.USE_SCHEDULED_RELEASE = savedScheduledRelease; + } + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/IoSchedulerInternalTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/IoSchedulerInternalTest.java new file mode 100644 index 00000000000..9a4b6f3be0c --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/IoSchedulerInternalTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.schedulers; + +import static org.junit.Assert.*; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.RxJavaTest; +import io.reactivex.rxjava3.disposables.CompositeDisposable; +import io.reactivex.rxjava3.internal.schedulers.IoScheduler.*; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class IoSchedulerInternalTest extends RxJavaTest { + + @Test + public void expiredQueueEmpty() { + ConcurrentLinkedQueue expire = new ConcurrentLinkedQueue<>(); + CompositeDisposable cd = new CompositeDisposable(); + + CachedWorkerPool.evictExpiredWorkers(expire, cd); + } + + @Test + public void expiredWorkerRemoved() { + ConcurrentLinkedQueue expire = new ConcurrentLinkedQueue<>(); + CompositeDisposable cd = new CompositeDisposable(); + + ThreadWorker tw = new ThreadWorker(new RxThreadFactory("IoExpiryTest")); + + try { + expire.add(tw); + cd.add(tw); + + CachedWorkerPool.evictExpiredWorkers(expire, cd); + + assertTrue(tw.isDisposed()); + assertTrue(expire.isEmpty()); + } finally { + tw.dispose(); + } + } + + @Test + public void noExpiredWorker() { + ConcurrentLinkedQueue expire = new ConcurrentLinkedQueue<>(); + CompositeDisposable cd = new CompositeDisposable(); + + ThreadWorker tw = new ThreadWorker(new RxThreadFactory("IoExpiryTest")); + tw.setExpirationTime(System.nanoTime() + 10_000_000_000L); + + try { + expire.add(tw); + cd.add(tw); + + CachedWorkerPool.evictExpiredWorkers(expire, cd); + + assertFalse(tw.isDisposed()); + assertFalse(expire.isEmpty()); + } finally { + tw.dispose(); + } + } + + @Test + public void expireReuseRace() { + ConcurrentLinkedQueue expire = new ConcurrentLinkedQueue<>(); + CompositeDisposable cd = new CompositeDisposable(); + + ThreadWorker tw = new ThreadWorker(new RxThreadFactory("IoExpiryTest")); + tw.dispose(); + + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + expire.add(tw); + cd.add(tw); + + TestHelper.race( + () -> CachedWorkerPool.evictExpiredWorkers(expire, cd), + () -> expire.remove(tw) + ); + } + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/RxThreadFactoryTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/RxThreadFactoryTest.java index 83a65e65ac9..d0cbb6a476a 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/RxThreadFactoryTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/RxThreadFactoryTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/ScheduledDirectPeriodicTaskTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/ScheduledDirectPeriodicTaskTest.java index 23afeca2ce0..d41906b13a2 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/ScheduledDirectPeriodicTaskTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/ScheduledDirectPeriodicTaskTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,6 +13,8 @@ package io.reactivex.rxjava3.internal.schedulers; +import static org.junit.Assert.fail; + import java.util.List; import org.junit.Test; @@ -33,9 +35,14 @@ public void runnableThrows() { public void run() { throw new TestException(); } - }); - - task.run(); + }, true); + + try { + task.run(); + fail("Should have thrown!"); + } catch (TestException expected) { + // expected + } TestHelper.assertUndeliverable(errors, 0, TestException.class); } finally { diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/ScheduledRunnableTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/ScheduledRunnableTest.java index a8920fbd933..8d2fc1f7cce 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/ScheduledRunnableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/ScheduledRunnableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -208,7 +208,12 @@ public void run() { }, set); set.add(run); - run.run(); + try { + run.run(); + fail("Should have thrown!"); + } catch (TestException expected) { + // expected + } assertTrue(run.isDisposed()); @@ -394,4 +399,29 @@ public void withParentIsDisposed() { assertFalse(set.remove(run)); } + + @Test + public void toStringStates() { + CompositeDisposable set = new CompositeDisposable(); + ScheduledRunnable task = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, set); + + assertEquals("ScheduledRunnable[Waiting]", task.toString()); + + task.set(ScheduledRunnable.THREAD_INDEX, Thread.currentThread()); + + assertEquals("ScheduledRunnable[Running on " + Thread.currentThread() + "]", task.toString()); + + task.dispose(); + + assertEquals("ScheduledRunnable[Disposed(Sync)]", task.toString()); + + task.set(ScheduledRunnable.FUTURE_INDEX, ScheduledRunnable.DONE); + + assertEquals("ScheduledRunnable[Finished]", task.toString()); + + task = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, set); + task.dispose(); + + assertEquals("ScheduledRunnable[Disposed(Async)]", task.toString()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/SchedulerMultiWorkerSupportTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/SchedulerMultiWorkerSupportTest.java index 21b4514be1b..3d16867a1a3 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/SchedulerMultiWorkerSupportTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/SchedulerMultiWorkerSupportTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/SchedulerPoolFactoryTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/SchedulerPoolFactoryTest.java index 1fcbf105b4e..12afa708c45 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/SchedulerPoolFactoryTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/SchedulerPoolFactoryTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.schedulers; @@ -23,7 +20,6 @@ import io.reactivex.rxjava3.core.RxJavaTest; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.testsupport.TestHelper; public class SchedulerPoolFactoryTest extends RxJavaTest { @@ -33,50 +29,6 @@ public void utilityClass() { TestHelper.checkUtilityClass(SchedulerPoolFactory.class); } - @Test - public void multiStartStop() { - SchedulerPoolFactory.shutdown(); - - SchedulerPoolFactory.shutdown(); - - SchedulerPoolFactory.tryStart(false); - - assertNull(SchedulerPoolFactory.PURGE_THREAD.get()); - - SchedulerPoolFactory.start(); - - // restart schedulers - Schedulers.shutdown(); - - Schedulers.start(); - } - - @Test - public void startRace() throws InterruptedException { - try { - for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { - SchedulerPoolFactory.shutdown(); - - Runnable r1 = new Runnable() { - @Override - public void run() { - SchedulerPoolFactory.start(); - } - }; - - TestHelper.race(r1, r1); - } - - } finally { - // restart schedulers - Schedulers.shutdown(); - - Thread.sleep(200); - - Schedulers.start(); - } - } - @Test public void boolPropertiesDisabledReturnsDefaultDisabled() throws Throwable { assertTrue(SchedulerPoolFactory.getBooleanProperty(false, "key", false, true, failingPropertiesAccessor)); @@ -101,30 +53,6 @@ public void boolPropertiesReturnsValue() throws Throwable { assertFalse(SchedulerPoolFactory.getBooleanProperty(true, "false", false, true, Functions.identity())); } - @Test - public void intPropertiesDisabledReturnsDefaultDisabled() throws Throwable { - assertEquals(-1, SchedulerPoolFactory.getIntProperty(false, "key", 0, -1, failingPropertiesAccessor)); - assertEquals(-1, SchedulerPoolFactory.getIntProperty(false, "key", 1, -1, failingPropertiesAccessor)); - } - - @Test - public void intPropertiesEnabledMissingReturnsDefaultMissing() throws Throwable { - assertEquals(-1, SchedulerPoolFactory.getIntProperty(true, "key", -1, 0, missingPropertiesAccessor)); - assertEquals(-1, SchedulerPoolFactory.getIntProperty(true, "key", -1, 1, missingPropertiesAccessor)); - } - - @Test - public void intPropertiesFailureReturnsDefaultMissing() throws Throwable { - assertEquals(-1, SchedulerPoolFactory.getIntProperty(true, "key", -1, 0, failingPropertiesAccessor)); - assertEquals(-1, SchedulerPoolFactory.getIntProperty(true, "key", -1, 1, failingPropertiesAccessor)); - } - - @Test - public void intPropertiesReturnsValue() throws Throwable { - assertEquals(1, SchedulerPoolFactory.getIntProperty(true, "1", 0, 4, Functions.identity())); - assertEquals(2, SchedulerPoolFactory.getIntProperty(true, "2", 3, 5, Functions.identity())); - } - static final Function failingPropertiesAccessor = new Function() { @Override public String apply(String v) throws Throwable { @@ -138,22 +66,4 @@ public String apply(String v) throws Throwable { return null; } }; - - @Test - public void putIntoPoolNoPurge() { - int s = SchedulerPoolFactory.POOLS.size(); - - SchedulerPoolFactory.tryPutIntoPool(false, null); - - assertEquals(s, SchedulerPoolFactory.POOLS.size()); - } - - @Test - public void putIntoPoolNonThreadPool() { - int s = SchedulerPoolFactory.POOLS.size(); - - SchedulerPoolFactory.tryPutIntoPool(true, null); - - assertEquals(s, SchedulerPoolFactory.POOLS.size()); - } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/SchedulerWhenTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/SchedulerWhenTest.java index d48228d20cc..03e6a9300f5 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/SchedulerWhenTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/SchedulerWhenTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/SingleSchedulerTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/SingleSchedulerTest.java index f6dfe5e455f..c9f9cc54765 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/SingleSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/SingleSchedulerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,22 +14,25 @@ package io.reactivex.rxjava3.internal.schedulers; import static org.junit.Assert.*; +import static org.mockito.Mockito.*; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import org.junit.Test; import io.reactivex.rxjava3.core.Scheduler; import io.reactivex.rxjava3.core.Scheduler.Worker; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.internal.schedulers.SingleScheduler.ScheduledWorker; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.*; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class SingleSchedulerTest extends AbstractSchedulerTests { @Test + @SuppressUndeliverable public void shutdownRejects() { final int[] calls = { 0 }; @@ -123,4 +126,20 @@ public void runnableDisposedAsyncTimed() throws Exception { return Schedulers.single(); } + @Test + public void zeroPeriodRejectedExecution() throws Throwable { + TestHelper.withErrorTracking(errors -> { + Scheduler s = RxJavaPlugins.createSingleScheduler(new RxThreadFactory("Test")); + s.shutdown(); + Runnable run = mock(Runnable.class); + + s.schedulePeriodicallyDirect(run, 1, 0, TimeUnit.MILLISECONDS); + + Thread.sleep(100); + + verify(run, never()).run(); + + TestHelper.assertUndeliverable(errors, 0, RejectedExecutionException.class); + }); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/schedulers/TrampolineSchedulerInternalTest.java b/src/test/java/io/reactivex/rxjava3/internal/schedulers/TrampolineSchedulerInternalTest.java index e30400214c1..b25620e2bfa 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/schedulers/TrampolineSchedulerInternalTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/schedulers/TrampolineSchedulerInternalTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.schedulers; @@ -20,19 +17,23 @@ import static org.mockito.Mockito.*; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; -import io.reactivex.rxjava3.core.RxJavaTest; +import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Scheduler.Worker; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.EmptyDisposable; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.internal.schedulers.TrampolineScheduler.*; import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.testsupport.*; public class TrampolineSchedulerInternalTest extends RxJavaTest { @Test + @SuppressUndeliverable public void scheduleDirectInterrupt() { Thread.currentThread().interrupt(); @@ -144,6 +145,7 @@ public void run() { } @Test + @SuppressUndeliverable public void reentrantScheduleInterrupt() { final Worker w = Schedulers.trampoline().createWorker(); try { @@ -209,4 +211,29 @@ public void run() { verify(r, never()).run(); } + + @Test + public void submitAndDisposeNextTask() { + Scheduler.Worker w = Schedulers.trampoline().createWorker(); + + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + Runnable run = mock(Runnable.class); + + AtomicInteger sync = new AtomicInteger(2); + + w.schedule(() -> { + Disposable d = w.schedule(run); + + Schedulers.single().scheduleDirect(() -> { + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + d.dispose(); + }); + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + }); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableConditionalSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableConditionalSubscriberTest.java index c84e3807016..c58d015abc9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableConditionalSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableConditionalSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,15 +14,18 @@ package io.reactivex.rxjava3.internal.subscribers; import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; import org.junit.Test; import org.reactivestreams.Subscription; -import io.reactivex.rxjava3.annotations.Nullable; -import io.reactivex.rxjava3.core.RxJavaTest; -import io.reactivex.rxjava3.internal.fuseable.ConditionalSubscriber; -import io.reactivex.rxjava3.internal.subscriptions.ScalarSubscription; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.annotations.*; +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.internal.subscriptions.*; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.testsupport.*; public class BasicFuseableConditionalSubscriberTest extends RxJavaTest { @@ -83,4 +86,172 @@ public Integer poll() throws Exception { fcs.clear(); assertTrue(fcs.isEmpty()); } + + @Test + public void implementationStopsOnSubscribe() { + @SuppressWarnings("unchecked") + ConditionalSubscriber ts = mock(ConditionalSubscriber.class); + + BasicFuseableConditionalSubscriber bfs = new BasicFuseableConditionalSubscriber(ts) { + + @Override + protected boolean beforeDownstream() { + return false; + } + + @Override + public void onNext(@NonNull Integer t) { + ts.onNext(t); + } + + @Override + public int requestFusion(int mode) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public boolean tryOnNext(@NonNull Integer t) { + // TODO Auto-generated method stub + return false; + } + + @Override + public @Nullable Integer poll() throws Throwable { + return null; + } + }; + + bfs.onSubscribe(new BooleanSubscription()); + + verify(ts, never()).onSubscribe(any()); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f + .map(v -> v) + .filter(v -> true) + ); + } + + @Test + public void transitiveBoundaryFusionNone() { + @SuppressWarnings("unchecked") + ConditionalSubscriber ts = mock(ConditionalSubscriber.class); + + BasicFuseableConditionalSubscriber bfs = new BasicFuseableConditionalSubscriber(ts) { + + @Override + protected boolean beforeDownstream() { + return false; + } + + @Override + public void onNext(@NonNull Integer t) { + ts.onNext(t); + } + + @Override + public int requestFusion(int mode) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public boolean tryOnNext(@NonNull Integer t) { + // TODO Auto-generated method stub + return false; + } + + @Override + public @Nullable Integer poll() throws Throwable { + return null; + } + }; + + bfs.onSubscribe(new BooleanSubscription()); + + assertEquals(QueueFuseable.NONE, bfs.transitiveBoundaryFusion(QueueFuseable.ANY)); + } + + @Test + public void transitiveBoundaryFusionAsync() { + @SuppressWarnings("unchecked") + ConditionalSubscriber ts = mock(ConditionalSubscriber.class); + + BasicFuseableConditionalSubscriber bfs = new BasicFuseableConditionalSubscriber(ts) { + + @Override + protected boolean beforeDownstream() { + return false; + } + + @Override + public void onNext(@NonNull Integer t) { + ts.onNext(t); + } + + @Override + public int requestFusion(int mode) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public boolean tryOnNext(@NonNull Integer t) { + // TODO Auto-generated method stub + return false; + } + + @Override + public @Nullable Integer poll() throws Throwable { + return null; + } + }; + + bfs.onSubscribe(EmptySubscription.INSTANCE); + + assertEquals(QueueFuseable.ASYNC, bfs.transitiveBoundaryFusion(QueueFuseable.ANY)); + } + + @Test + public void transitiveBoundaryFusionAsyncBoundary() { + @SuppressWarnings("unchecked") + ConditionalSubscriber ts = mock(ConditionalSubscriber.class); + + BasicFuseableConditionalSubscriber bfs = new BasicFuseableConditionalSubscriber(ts) { + + @Override + protected boolean beforeDownstream() { + return false; + } + + @Override + public void onNext(@NonNull Integer t) { + ts.onNext(t); + } + + @Override + public int requestFusion(int mode) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public boolean tryOnNext(@NonNull Integer t) { + // TODO Auto-generated method stub + return false; + } + + @Override + public @Nullable Integer poll() throws Throwable { + return null; + } + }; + + bfs.onSubscribe(EmptySubscription.INSTANCE); + + assertEquals(QueueFuseable.NONE, bfs.transitiveBoundaryFusion(QueueFuseable.ANY | QueueFuseable.BOUNDARY)); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableSubscriberTest.java index 87ccd91b92f..d6f85acc468 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/BasicFuseableSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,9 +17,9 @@ import org.junit.Test; -import io.reactivex.rxjava3.annotations.Nullable; +import io.reactivex.rxjava3.annotations.*; import io.reactivex.rxjava3.core.RxJavaTest; -import io.reactivex.rxjava3.internal.subscriptions.ScalarSubscription; +import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.TestHelper; @@ -53,4 +53,36 @@ public Integer poll() throws Exception { fcs.clear(); assertTrue(fcs.isEmpty()); } + + @Test + public void implementationStopsOnSubscribe() { + TestSubscriber ts = new TestSubscriber<>(); + BasicFuseableSubscriber bfs = new BasicFuseableSubscriber(ts) { + + @Override + protected boolean beforeDownstream() { + return false; + } + + @Override + public void onNext(@NonNull Integer t) { + ts.onNext(t); + } + + @Override + public int requestFusion(int mode) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public @Nullable Integer poll() throws Throwable { + return null; + } + }; + + bfs.onSubscribe(new BooleanSubscription()); + + assertFalse(ts.hasSubscription()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/BlockingSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/BlockingSubscriberTest.java index 563a52a9840..a97f4ee93e7 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscribers/BlockingSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/BlockingSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/BoundedSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/BoundedSubscriberTest.java index d6b80cc8733..68e955097da 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscribers/BoundedSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/BoundedSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,7 +27,7 @@ import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class BoundedSubscriberTest extends RxJavaTest { @@ -315,6 +315,7 @@ public void accept(Subscription s) throws Exception { } @Test + @SuppressUndeliverable public void badSourceEmitAfterDone() { Flowable source = Flowable.fromPublisher(new Publisher() { @Override @@ -378,4 +379,37 @@ public void customOnErrorShouldReportCustomOnError() { assertTrue(subscriber.hasCustomOnError()); } + + @Test + public void cancel() { + BoundedSubscriber subscriber = new BoundedSubscriber<>(Functions.emptyConsumer(), + Functions.emptyConsumer(), + Functions.EMPTY_ACTION, + Functions.boundedConsumer(128), 128); + + BooleanSubscription bs = new BooleanSubscription(); + subscriber.onSubscribe(bs); + + subscriber.cancel(); + + assertTrue(bs.isCancelled()); + } + + @Test + public void dispose() { + BoundedSubscriber subscriber = new BoundedSubscriber<>(Functions.emptyConsumer(), + Functions.emptyConsumer(), + Functions.EMPTY_ACTION, + Functions.boundedConsumer(128), 128); + + BooleanSubscription bs = new BooleanSubscription(); + subscriber.onSubscribe(bs); + + assertFalse(subscriber.isDisposed()); + + subscriber.dispose(); + + assertTrue(bs.isCancelled()); + assertTrue(subscriber.isDisposed()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/DeferredScalarSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/DeferredScalarSubscriberTest.java index 698fcc18acb..dcfcb82377f 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscribers/DeferredScalarSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/DeferredScalarSubscriberTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.internal.subscribers; diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/EmptyComponentTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/EmptyComponentTest.java index 60da2b7a29e..c5cf3c88ca1 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscribers/EmptyComponentTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/EmptyComponentTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/FlowableConsumersTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/FlowableConsumersTest.java new file mode 100644 index 00000000000..cc7083cde7d --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/FlowableConsumersTest.java @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +/* + * Copyright 2016-2019 David Karnok + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.reactivex.rxjava3.internal.subscribers; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.util.*; + +import org.junit.Test; +import org.reactivestreams.Subscriber; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.exceptions.*; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.observers.LambdaConsumerIntrospection; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.processors.PublishProcessor; +import io.reactivex.rxjava3.testsupport.TestHelper; + +public class FlowableConsumersTest implements Consumer, Action { + + final CompositeDisposable composite = new CompositeDisposable(); + + final PublishProcessor processor = PublishProcessor.create(); + + final List events = new ArrayList<>(); + + @Override + public void run() throws Exception { + events.add("OnComplete"); + } + + @Override + public void accept(Object t) throws Exception { + events.add(t); + } + + static Disposable subscribeAutoDispose(Flowable source, CompositeDisposable composite, + Consumer onNext, Consumer onError, Action onComplete) { + return source.subscribe(onNext, onError, onComplete, composite); + } + + @Test + public void onNextNormal() { + + Disposable d = subscribeAutoDispose(processor, composite, this, Functions.ON_ERROR_MISSING, () -> { }); + + assertFalse(d.getClass().toString(), ((LambdaConsumerIntrospection)d).hasCustomOnError()); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onNext(1); + + assertTrue(composite.size() > 0); + + assertEquals(Arrays.asList(1), events); + + processor.onComplete(); + + assertEquals(Arrays.asList(1), events); + + assertEquals(0, composite.size()); + } + + @Test + public void onErrorNormal() { + + subscribeAutoDispose(processor, composite, this, this, () -> { }); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onNext(1); + + assertTrue(composite.size() > 0); + + assertEquals(Arrays.asList(1), events); + + processor.onComplete(); + + assertEquals(Arrays.asList(1), events); + + assertEquals(0, composite.size()); + } + + @Test + public void onErrorError() { + + Disposable d = subscribeAutoDispose(processor, composite, this, this, this); + + assertTrue(d.getClass().toString(), ((LambdaConsumerIntrospection)d).hasCustomOnError()); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onNext(1); + + assertTrue(composite.size() > 0); + + assertEquals(Arrays.asList(1), events); + + processor.onError(new IOException()); + + assertEquals(events.toString(), 1, events.get(0)); + assertTrue(events.toString(), events.get(1) instanceof IOException); + + assertEquals(0, composite.size()); + } + + @Test + public void onCompleteNormal() { + + subscribeAutoDispose(processor, composite, this, this, this); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onNext(1); + + assertTrue(composite.size() > 0); + + assertEquals(Arrays.asList(1), events); + + processor.onComplete(); + + assertEquals(Arrays.asList(1, "OnComplete"), events); + + assertEquals(0, composite.size()); + } + + @Test + public void onCompleteError() { + + subscribeAutoDispose(processor, composite, this, this, this); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + processor.onNext(1); + + assertTrue(composite.size() > 0); + + assertEquals(Arrays.asList(1), events); + + processor.onError(new IOException()); + + assertEquals(events.toString(), 1, events.get(0)); + assertTrue(events.toString(), events.get(1) instanceof IOException); + + assertEquals(0, composite.size()); + } + + @Test + public void onCompleteDispose() { + + Disposable d = subscribeAutoDispose(processor, composite, this, this, this); + + assertTrue(composite.size() > 0); + + assertTrue(events.toString(), events.isEmpty()); + + assertFalse(d.isDisposed()); + + d.dispose(); + d.dispose(); + + assertTrue(d.isDisposed()); + + assertEquals(0, composite.size()); + + assertFalse(processor.hasSubscribers()); + } + + @Test + public void onNextCrash() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose(processor, composite, new Consumer() { + @Override + public void accept(Object t) throws Exception { + throw new IOException(); + } + }, this, this); + + processor.onNext(1); + + assertTrue(errors.toString(), errors.isEmpty()); + + assertTrue(events.toString(), events.get(0) instanceof IOException); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void onNextCrashOnError() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose(processor, composite, this, new Consumer() { + @Override + public void accept(Throwable t) throws Exception { + throw new IOException(t); + } + }, this); + + processor.onError(new IllegalArgumentException()); + + assertTrue(events.toString(), events.isEmpty()); + + TestHelper.assertError(errors, 0, CompositeException.class); + List inners = TestHelper.compositeList(errors.get(0)); + TestHelper.assertError(inners, 0, IllegalArgumentException.class); + TestHelper.assertError(inners, 1, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void onNextCrashNoError() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose(processor, composite, new Consumer() { + @Override + public void accept(Object t) throws Exception { + throw new IOException(); + } + }, Functions.ON_ERROR_MISSING, () -> { }); + + processor.onNext(1); + + assertTrue(events.toString(), events.isEmpty()); + + TestHelper.assertError(errors, 0, OnErrorNotImplementedException.class); + assertTrue(errors.get(0).getCause() instanceof IOException); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void onCompleteCrash() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose(processor, composite, this, this, new Action() { + @Override + public void run() throws Exception { + throw new IOException(); + } + }); + + processor.onNext(1); + processor.onComplete(); + + assertEquals(Arrays.asList(1), events); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } + + @Test + public void badSource() { + List errors = TestHelper.trackPluginErrors(); + try { + subscribeAutoDispose( + new Flowable() { + @Override + protected void subscribeActual( + Subscriber s) { + s.onSubscribe(new BooleanSubscription()); + s.onNext(1); + s.onComplete(); + + s.onSubscribe(new BooleanSubscription()); + s.onNext(2); + s.onComplete(); + s.onError(new IOException()); + } + }, composite, this, this, this + ); + + assertEquals(Arrays.asList(1, "OnComplete"), events); + + TestHelper.assertUndeliverable(errors, 0, IOException.class); + } finally { + RxJavaPlugins.reset(); + } + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/FutureSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/FutureSubscriberTest.java index 69450f2ad05..56de26e5d61 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscribers/FutureSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/FutureSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,7 @@ import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.Schedulers; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class FutureSubscriberTest extends RxJavaTest { @@ -155,6 +155,7 @@ public void run() { } @Test + @SuppressUndeliverable public void onErrorCancelRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { final FutureSubscriber fs = new FutureSubscriber<>(); @@ -180,6 +181,7 @@ public void run() { } @Test + @SuppressUndeliverable public void onCompleteCancelRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { final FutureSubscriber fs = new FutureSubscriber<>(); @@ -211,6 +213,7 @@ public void run() { } @Test + @SuppressUndeliverable public void onErrorOnComplete() throws Exception { fs.onError(new TestException("One")); fs.onComplete(); @@ -224,6 +227,7 @@ public void onErrorOnComplete() throws Exception { } @Test + @SuppressUndeliverable public void onCompleteOnError() throws Exception { fs.onComplete(); fs.onError(new TestException("One")); @@ -236,6 +240,7 @@ public void onCompleteOnError() throws Exception { } @Test + @SuppressUndeliverable public void cancelOnError() throws Exception { fs.cancel(true); fs.onError(new TestException("One")); @@ -249,6 +254,7 @@ public void cancelOnError() throws Exception { } @Test + @SuppressUndeliverable public void cancelOnComplete() throws Exception { fs.cancel(true); fs.onComplete(); @@ -292,4 +298,20 @@ public void getTimedOut() throws Exception { assertEquals(timeoutMessage(1, TimeUnit.NANOSECONDS), expected.getMessage()); } } + + @Test + public void onNextCompleteOnError() throws Exception { + List errors = TestHelper.trackPluginErrors(); + try { + fs.onNext(1); + fs.onComplete(); + fs.onError(new TestException("One")); + + assertEquals((Integer)1, fs.get(5, TimeUnit.MILLISECONDS)); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + } finally { + RxJavaPlugins.reset(); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/InnerQueuedSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/InnerQueuedSubscriberTest.java index e6533166cec..7856ce5d3ea 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscribers/InnerQueuedSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/InnerQueuedSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/LambdaSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/LambdaSubscriberTest.java index 17e4fb2fc95..e7f3931096c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscribers/LambdaSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/LambdaSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -28,7 +28,7 @@ import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class LambdaSubscriberTest extends RxJavaTest { @@ -246,6 +246,7 @@ public void accept(Subscription s) throws Exception { } @Test + @SuppressUndeliverable public void badSourceEmitAfterDone() { Flowable source = Flowable.fromPublisher(new Publisher() { @Override diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/QueueDrainSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/QueueDrainSubscriberTest.java index 6d09484d559..985705b0e7c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscribers/QueueDrainSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/QueueDrainSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,8 +23,8 @@ import io.reactivex.rxjava3.core.RxJavaTest; import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.MissingBackpressureException; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.SpscArrayQueue; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.TestHelper; diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/SinglePostCompleteSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/SinglePostCompleteSubscriberTest.java index 1a9bb1310b0..8616e6ba3be 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscribers/SinglePostCompleteSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/SinglePostCompleteSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/StrictSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/StrictSubscriberTest.java index 1b36462c470..ba4548d02ec 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscribers/StrictSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/StrictSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscribers/SubscriberResourceWrapperTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscribers/SubscriberResourceWrapperTest.java index bafc579b639..65f2817354e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscribers/SubscriberResourceWrapperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscribers/SubscriberResourceWrapperTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/ArrayCompositeSubscriptionTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/ArrayCompositeSubscriptionTest.java index 9dd0cab6a5b..fc54cfe3570 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/ArrayCompositeSubscriptionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/ArrayCompositeSubscriptionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/AsyncSubscriptionTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/AsyncSubscriptionTest.java index 30d93a22ae3..0375d72ba57 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/AsyncSubscriptionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/AsyncSubscriptionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscriptionTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscriptionTest.java index dfe9e83f89f..7ea8d58c3fe 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscriptionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/DeferredScalarSubscriptionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,7 +18,7 @@ import org.junit.Test; import io.reactivex.rxjava3.core.RxJavaTest; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.TestHelper; diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/QueueSubscriptionTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/QueueSubscriptionTest.java index fb3f66397f6..92c37e0e526 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/QueueSubscriptionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/QueueSubscriptionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/ScalarSubscriptionTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/ScalarSubscriptionTest.java index 55a564280c4..377691e0a25 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/ScalarSubscriptionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/ScalarSubscriptionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionArbiterTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionArbiterTest.java index 4651b2e3b82..7bc7eb937aa 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionArbiterTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionArbiterTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionHelperTest.java b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionHelperTest.java index 13a2dc61aa5..9bb222fbb83 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionHelperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/subscriptions/SubscriptionHelperTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/AtomicThrowableTest.java b/src/test/java/io/reactivex/rxjava3/internal/util/AtomicThrowableTest.java index efe3b5c7b20..152039fac3e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/AtomicThrowableTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/AtomicThrowableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/BackpressureHelperTest.java b/src/test/java/io/reactivex/rxjava3/internal/util/BackpressureHelperTest.java index ca0b0e26689..d13cde57beb 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/BackpressureHelperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/BackpressureHelperTest.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.util; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/BlockingHelperTest.java b/src/test/java/io/reactivex/rxjava3/internal/util/BlockingHelperTest.java index 419febcaee5..0218185f08e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/BlockingHelperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/BlockingHelperTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/CrashingIterable.java b/src/test/java/io/reactivex/rxjava3/internal/util/CrashingIterable.java index bb053c23b0e..6bdbea27b15 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/CrashingIterable.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/CrashingIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/CrashingMappedIterable.java b/src/test/java/io/reactivex/rxjava3/internal/util/CrashingMappedIterable.java index caf09b372e0..d6b9491e2b5 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/CrashingMappedIterable.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/CrashingMappedIterable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/EndConsumerHelperTest.java b/src/test/java/io/reactivex/rxjava3/internal/util/EndConsumerHelperTest.java index 1cb96e732f0..8ad19429464 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/EndConsumerHelperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/EndConsumerHelperTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/ExceptionHelperTest.java b/src/test/java/io/reactivex/rxjava3/internal/util/ExceptionHelperTest.java index 70b70aea1f7..130cf5767be 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/ExceptionHelperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/ExceptionHelperTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/HalfSerializerObserverTest.java b/src/test/java/io/reactivex/rxjava3/internal/util/HalfSerializerObserverTest.java index cbb66e6425f..ea8c405849b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/HalfSerializerObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/HalfSerializerObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.util; import static org.junit.Assert.assertTrue; @@ -160,6 +161,7 @@ public void onComplete() { } @Test + @SuppressUndeliverable @SuppressWarnings({ "rawtypes", "unchecked" }) public void reentrantErrorOnError() { final AtomicInteger wip = new AtomicInteger(); @@ -234,6 +236,7 @@ public void run() { } @Test + @SuppressUndeliverable public void onErrorOnCompleteRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/HalfSerializerSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/internal/util/HalfSerializerSubscriberTest.java index 44eea4907cb..19198646481 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/HalfSerializerSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/HalfSerializerSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.util; import static org.junit.Assert.assertTrue; @@ -166,6 +167,7 @@ public void onComplete() { } @Test + @SuppressUndeliverable @SuppressWarnings({ "rawtypes", "unchecked" }) public void reentrantErrorOnError() { final AtomicInteger wip = new AtomicInteger(); @@ -240,6 +242,7 @@ public void run() { } @Test + @SuppressUndeliverable public void onErrorOnCompleteRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/JavadocNoThrows.java b/src/test/java/io/reactivex/rxjava3/internal/util/JavadocNoThrows.java new file mode 100644 index 00000000000..1a55807dd08 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/util/JavadocNoThrows.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.util; + +import java.io.File; +import java.nio.file.Files; +import java.util.List; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.parallel.ParallelFlowable; +import io.reactivex.rxjava3.testsupport.TestHelper; + +/** + * Scan the JavaDocs of the base classes and list those which do not have the {@code @throws} tag. + * The lack is not an error by itself but worth looking at. + */ +public final class JavadocNoThrows { + + private JavadocNoThrows() { + throw new IllegalArgumentException("No instances!"); + } + + public static void main(String[] args) throws Exception { + for (Class clazz : CLASSES) { + String clazzName = clazz.getSimpleName(); + String packageName = clazz.getPackage().getName(); + File f = TestHelper.findSource(clazzName, packageName); + + List lines = Files.readAllLines(f.toPath()); + + for (int i = 1; i < lines.size(); i++) { + String line = lines.get(i).trim(); + + if (line.startsWith("/**")) { + boolean found = false; + for (int j = i + 1; j < lines.size(); j++) { + + String line2 = lines.get(j).trim(); + if (line2.startsWith("public")) { + if (line2.endsWith("() {")) { + found = true; + } + break; + } + if (line2.startsWith("* @throws")) { + found = true; + break; + } + } + + if (!found) { + System.out.printf(" at %s.%s.method(%s.java:%s)%n%n", packageName, clazzName, clazzName, i + 1); + } + } + } + } + } + + static final Class[] CLASSES = { + Flowable.class, Observable.class, Maybe.class, Single.class, Completable.class, ParallelFlowable.class + }; +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/MarbleDimensions.java b/src/test/java/io/reactivex/rxjava3/internal/util/MarbleDimensions.java new file mode 100644 index 00000000000..2fdc7fe2d61 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/util/MarbleDimensions.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.util; + +import java.awt.image.BufferedImage; +import java.io.*; +import java.net.URL; +import java.nio.file.Files; +import java.util.*; +import java.util.regex.*; + +import javax.imageio.ImageIO; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.parallel.ParallelFlowable; +import io.reactivex.rxjava3.testsupport.TestHelper; + +/** + * Parses the main sources, locates the {@code } tags, downloads + * the referenced image and checks if the scaled dimensions are correct. + */ +public final class MarbleDimensions { + + /** Helper program. */ + private MarbleDimensions() { + throw new IllegalStateException("No instances!"); + } + + public static void main(String[] args) throws Throwable { + Pattern p = Pattern.compile("\\s*\\*\\s*\\ dimensions = new HashMap<>(); + + for (Class clazz : CLASSES) { + String simpleName = clazz.getSimpleName(); + System.out.println(simpleName); + System.out.println("----"); + String packageName = clazz.getPackage().getName(); + + File f = TestHelper.findSource(clazz.getSimpleName(), packageName); + if (f == null) { + System.err.println("Unable to locate " + clazz); + continue; + } + + List lines = Files.readAllLines(f.toPath()); + + for (int i = 0; i < lines.size(); i++) { + Matcher m = p.matcher(lines.get(i)); + if (m.matches()) { + int width = Integer.parseInt(m.group(2)); + int height = Integer.parseInt(m.group(5)); + String url = m.group(8); + + Integer[] imageDim = dimensions.get(url); + if (imageDim == null) { + Thread.sleep(SLEEP_PER_IMAGE_MILLIS); + + try { + BufferedImage bimg = ImageIO.read(new URL(url)); + + if (bimg == null) { + throw new IOException("not found"); + } + imageDim = new Integer[] { 0, 0 }; + imageDim[0] = bimg.getWidth(); + imageDim[1] = bimg.getHeight(); + + dimensions.put(url, imageDim); + } catch (IOException ex) { + System.err.printf("%s => %s%n", url, ex); + System.err.printf(" at %s.%s.method(%s.java:%d)%n", packageName, simpleName, simpleName, i + 1); + } + } + + if (imageDim != null) { + int expectedHeight = (int)Math.round(1.0 * width / imageDim[0] * imageDim[1]); + + if (expectedHeight != height) { + System.out.printf(" %d => %d%n", height, expectedHeight); + System.out.printf(" at %s.%s.method(%s.java:%d)%n", packageName, simpleName, simpleName, i + 1); + } + } + // System.out.printf("%d: %d x %d => %s%n", i + 1, width, height, url); + } + } + } + } + + static final int SLEEP_PER_IMAGE_MILLIS = 25; + + static final Class[] CLASSES = { + Flowable.class, Observable.class, Maybe.class, Single.class, Completable.class, ParallelFlowable.class + }; +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/MergerBiFunctionTest.java b/src/test/java/io/reactivex/rxjava3/internal/util/MergerBiFunctionTest.java index dce15c4b28c..b8a5f8b8433 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/MergerBiFunctionTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/MergerBiFunctionTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/MiscUtilTest.java b/src/test/java/io/reactivex/rxjava3/internal/util/MiscUtilTest.java index b27279eb432..adc779a302c 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/MiscUtilTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/MiscUtilTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -60,9 +60,13 @@ public void errorModeEnum() { @Test public void linkedArrayList() { LinkedArrayList list = new LinkedArrayList(2); + assertEquals(0, list.size()); list.add(1); + assertEquals(1, list.size()); list.add(2); + assertEquals(2, list.size()); list.add(3); + assertEquals(3, list.size()); assertEquals("[1, 2, 3]", list.toString()); } diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/NotificationLiteTest.java b/src/test/java/io/reactivex/rxjava3/internal/util/NotificationLiteTest.java index 7e701ff5b96..7638a98ead9 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/NotificationLiteTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/NotificationLiteTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/ObservableToFlowabeTestSync.java b/src/test/java/io/reactivex/rxjava3/internal/util/ObservableToFlowabeTestSync.java index fbe13a185e2..7bf668e2f1e 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/ObservableToFlowabeTestSync.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/ObservableToFlowabeTestSync.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/OpenHashSetTest.java b/src/test/java/io/reactivex/rxjava3/internal/util/OpenHashSetTest.java index c87bd13192f..f8c1bdf04da 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/OpenHashSetTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/OpenHashSetTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/OperatorArgumentNaming.java b/src/test/java/io/reactivex/rxjava3/internal/util/OperatorArgumentNaming.java new file mode 100644 index 00000000000..1814a26bbc0 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/util/OperatorArgumentNaming.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.util; + +import java.lang.reflect.*; +import java.util.*; + +import org.reactivestreams.*; + +import com.google.common.base.Strings; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.core.Observable; + +/** + * Compare method argument naming across base classes. + * This is not a full test because some naming mismatch is legitimate, such as singular in Maybe/Single and + * plural in Flowable/Observable + */ +public final class OperatorArgumentNaming { + + private OperatorArgumentNaming() { + throw new IllegalStateException("No instances!"); + } + + /** Classes to compare with each other. */ + static final Class[] CLASSES = { Flowable.class, Observable.class, Maybe.class, Single.class, Completable.class }; + + /** Types that refer to a reactive type and is generally matching the parent class; for comparison, these have to be unified. */ + static final Set> BASE_TYPE_SET = new HashSet<>(Arrays.asList( + Flowable.class, Publisher.class, Subscriber.class, FlowableSubscriber.class, + Observable.class, ObservableSource.class, Observer.class, + Maybe.class, MaybeSource.class, MaybeObserver.class, + Single.class, SingleSource.class, SingleObserver.class, + Completable.class, CompletableSource.class, CompletableObserver.class + )); + + public static void main(String[] args) { + // className -> methodName -> overloads -> arguments + Map>>> map = new HashMap<>(); + + for (Class clazz : CLASSES) { + Map>> classMethods = map.computeIfAbsent(clazz.getSimpleName(), v -> new HashMap<>()); + for (Method method : clazz.getDeclaredMethods()) { + if (method.getDeclaringClass() == clazz && method.getParameterCount() != 0) { + List> overloads = classMethods.computeIfAbsent(method.getName(), v -> new ArrayList<>()); + + List overload = new ArrayList<>(); + overloads.add(overload); + + for (Parameter param : method.getParameters()) { + String typeName; + Class type = param.getType(); + if (type.isArray()) { + Class componentType = type.getComponentType(); + if (BASE_TYPE_SET.contains(componentType)) { + typeName = "BaseType"; + } else { + typeName = type.getComponentType().getSimpleName() + "[]"; + } + } else + if (BASE_TYPE_SET.contains(type)) { + typeName = "BaseType"; + } else { + typeName = type.getSimpleName(); + } + String name = param.getName(); + if (name.equals("bufferSize") || name.equals("prefetch") || name.equals("capacityHint")) { + name = "bufferSize|prefetch|capacityHint"; + } + if (name.equals("subscriber") || name.equals("observer")) { + name = "subscriber|observer"; + } + if (name.contains("onNext")) { + name = name.replace("onNext", "onNext|onSuccess"); + } else + if (name.contains("onSuccess")) { + name = name.replace("onSuccess", "onNext|onSuccess"); + } + overload.add(new ArgumentNameAndType(typeName, name)); + } + } + } + } + + int counter = 0; + + for (int i = 0; i < CLASSES.length - 1; i++) { + String firstName = CLASSES[i].getSimpleName(); + Map>> firstClassMethods = map.get(firstName); + for (int j = i + 1; j < CLASSES.length; j++) { + String secondName = CLASSES[j].getSimpleName(); + Map>> secondClassMethods = map.get(secondName); + + for (Map.Entry>> methodOverloadsFirst : firstClassMethods.entrySet()) { + + List> methodOverloadsSecond = secondClassMethods.get(methodOverloadsFirst.getKey()); + + if (methodOverloadsSecond != null) { + for (List overloadFirst : methodOverloadsFirst.getValue()) { + for (List overloadSecond : methodOverloadsSecond) { + if (overloadFirst.size() == overloadSecond.size()) { + // Argument types match? + boolean match = true; + for (int k = 0; k < overloadFirst.size(); k++) { + if (!overloadFirst.get(k).type.equals(overloadSecond.get(k).type)) { + match = false; + break; + } + } + // Argument names match? + if (match) { + for (int k = 0; k < overloadFirst.size(); k++) { + if (!overloadFirst.get(k).name.equals(overloadSecond.get(k).name)) { + System.out.print("Argument naming mismatch #"); + System.out.println(++counter); + + System.out.print(" "); + System.out.print(Strings.padEnd(firstName, Math.max(firstName.length(), secondName.length()) + 1, ' ')); + System.out.print(methodOverloadsFirst.getKey()); + System.out.print(" "); + System.out.println(overloadFirst); + + System.out.print(" "); + System.out.print(Strings.padEnd(secondName, Math.max(firstName.length(), secondName.length()) + 1, ' ')); + System.out.print(methodOverloadsFirst.getKey()); + System.out.print(" "); + System.out.println(overloadSecond); + System.out.println(); + break; + } + } + } + } + } + } + } + } + } + } + } + + static final class ArgumentNameAndType { + final String type; + final String name; + + ArgumentNameAndType(String type, String name) { + this.type = type; + this.name = name; + } + + @Override + public String toString() { + return type + " " + name; + } + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/OperatorMatrixGenerator.java b/src/test/java/io/reactivex/rxjava3/internal/util/OperatorMatrixGenerator.java new file mode 100644 index 00000000000..9c5f058ff45 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/internal/util/OperatorMatrixGenerator.java @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.internal.util; + +import java.io.*; +import java.lang.reflect.Method; +import java.nio.file.*; +import java.util.*; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.core.Observable; + +/** + * Generate a table of available operators across base classes in {@code Operator-Matrix.md}. + * + * Should be run with the main project directory as working directory where the {@code docs} + * folder is. + */ +public final class OperatorMatrixGenerator { + + private OperatorMatrixGenerator() { + throw new IllegalStateException("No instances!"); + } + + static final String PRESENT = "![present](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_on.png)"; + static final String ABSENT = "![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_off.png)"; + static final String TBD = "![absent](https://raw.github.com/wiki/ReactiveX/RxJava/images/checkmark_half.png)"; + + static final Class[] CLASSES = { + Flowable.class, Observable.class, Maybe.class, Single.class, Completable.class + }; + + static String header(String type) { + return "![" + type + "](https://raw.github.com/wiki/ReactiveX/RxJava/images/opmatrix-" + type.toLowerCase() + ".png)"; + } + + public static void main(String[] args) throws IOException { + Set operatorSet = new HashSet<>(); + Map, Set> operatorMap = new HashMap<>(); + + for (Class clazz : CLASSES) { + Set set = operatorMap.computeIfAbsent(clazz, c -> new HashSet<>()); + + for (Method m : clazz.getMethods()) { + String name = m.getName(); + if (!name.equals("bufferSize") + && m.getDeclaringClass() == clazz + && !m.isSynthetic()) { + operatorSet.add(m.getName()); + set.add(m.getName()); + } + } + } + + List sortedOperators = new ArrayList<>(operatorSet); + sortedOperators.sort(Comparator.naturalOrder()); + + try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(Paths.get("docs", "Operator-Matrix.md"), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) { + out.print("Operator |"); + for (Class clazz : CLASSES) { + out.print(" "); + out.print(header(clazz.getSimpleName())); + out.print(" |"); + } + out.println(); + out.print("-----|"); + for (int i = 0; i < CLASSES.length; i++) { + out.print("---|"); + } + out.println(); + + Map notesMap = new HashMap<>(); + List notesList = new ArrayList<>(); + List tbdList = new ArrayList<>(); + int[] counters = new int[CLASSES.length]; + + for (String operatorName : sortedOperators) { + out.print("`"); + out.print(operatorName); + out.print("`|"); + int m = 0; + for (Class clazz : CLASSES) { + if (operatorMap.get(clazz).contains(operatorName)) { + out.print(PRESENT); + counters[m]++; + } else { + String notes = findNotes(clazz.getSimpleName(), operatorName); + if (notes != null) { + out.print(ABSENT); + Integer index = notesMap.get(notes); + if (index == null) { + index = notesMap.size() + 1; + notesMap.put(notes, index); + notesList.add(notes); + } + out.print(" (["); + out.print(index); + out.print("](#notes-"); + out.print(index); + out.print("))"); + } else { + out.print(TBD); + tbdList.add(clazz.getSimpleName() + "." + operatorName + "()"); + } + } + out.print("|"); + m++; + } + out.println(); + } + out.print("**"); + out.print(sortedOperators.size()); + out.print(" operators** |"); + for (int m = 0; m < counters.length; m++) { + out.print(" **"); + out.print(counters[m]); + out.print("** |"); + } + out.println(); + + if (!notesList.isEmpty()) { + out.println(); + out.println("#### Notes"); + + for (int i = 0; i < notesList.size(); i++) { + out.print(""); + out.print(i + 1); + out.print(" "); + out.print(notesList.get(i)); + out.println("
"); + } + } + if (tbdList.isEmpty()) { + out.println(); + out.println("#### Under development"); + out.println(); + out.println("*Currently, all intended operators are implemented.*"); + } else { + out.println(); + out.println("#### Under development"); + out.println(); + + for (int i = 0; i < tbdList.size(); i++) { + out.print(i + 1); + out.print(". "); + out.println(tbdList.get(i)); + } + } + } + } + + static String findNotes(String clazzName, String operatorName) { + Map classNotes = NOTES_MAP.get(operatorName); + if (classNotes != null) { + return classNotes.get(clazzName.substring(0, 1)); + } + switch (operatorName) { + case "empty": { + if ("Completable".equals(clazzName)) { + return "Use [`complete()`](#complete)."; + } + if ("Single".equals(clazzName)) { + return "Never empty."; + } + break; + } + } + return null; + } + + static final String[] NOTES = { + // Format + // FOMSC methodName note + " MS all Use [`contains()`](#contains).", + " C all Always empty.", + "FOMS andThen Use [`concatWith`](#concatWith).", + " MS any Use [`contains()`](#contains).", + " C any Always empty.", + "FO blockingAwait Use [`blockingFirst()`](#blockingFirst), [`blockingSingle()`](#blockingSingle) or [`blockingLast()`](#blockingLast).", + " MS blockingAwait Use [`blockingGet()`](#blockingGet).", + " MS blockingFirst At most one element to get. Use [`blockingGet()`](#blockingGet).", + " C blockingFirst No elements to get. Use [`blockingAwait()`](#blockingAwait).", + " MSC blockingForEach Use [`blockingSubscribe()`](#blockingSubscribe)", + "FO blockingGet Use [`blockingFirst()`](#blockingFirst), [`blockingSingle()`](#blockingSingle) or [`blockingLast()`](#blockingLast).", + " C blockingGet No elements to get. Use [`blockingAwait()`](#blockingAwait).", + " MS blockingIterable At most one element to get. Use [`blockingGet()`](#blockingGet).", + " C blockingIterable No elements to get. Use [`blockingAwait()`](#blockingAwait).", + " MS blockingLast At most one element to get. Use [`blockingGet()`](#blockingGet).", + " C blockingLast No elements to get. Use [`blockingAwait()`](#blockingAwait).", + " MS blockingLatest At most one element to get. Use [`blockingGet()`](#blockingGet).", + " C blockingLatest No elements to get. Use [`blockingAwait()`](#blockingAwait).", + " MS blockingMostRecent At most one element to get. Use [`blockingGet()`](#blockingGet).", + " C blockingMostRecent No elements to get. Use [`blockingAwait()`](#blockingAwait).", + " MS blockingNext At most one element to get. Use [`blockingGet()`](#blockingGet).", + " C blockingNext No elements to get. Use [`blockingAwait()`](#blockingAwait).", + " MS blockingSingle At most one element to get. Use [`blockingGet()`](#blockingGet).", + " C blockingSingle No elements to get. Use [`blockingAwait()`](#blockingAwait).", + " MS blockingStream At most one element to get. Use [`blockingGet()`](#blockingGet).", + " C blockingStream No elements to get. Use [`blockingAwait()`](#blockingAwait).", + " M buffer Use [`map()`](#map) and [`switchIfEmpty()`](#switchIfEmpty) to transform into a list/collection.", + " S buffer Use [`map()`](#map) to transform into a list/collection.", + " C buffer Always empty. Use [`andThen()`](#andThen) to bring in a list/collection.", + " MSC cacheWithInitialCapacity At most one element to store. Use [`cache()`](#cache).", + " C cast Always empty.", + " M collect At most one element to collect. Use [`map()`](#map) and [`switchIfEmpty()`](#switchIfEmpty) to transform into a list/collection.", + " S collect One element to collect. Use [`map()`](#map) to transform into a list/collection.", + " C collect Always empty. Use [`andThen()`](#andThen) to bring in a collection.", + " M collectInto At most one element to collect. Use [`map()`](#map) and [`switchIfEmpty()`](#switchIfEmpty) to transform into a list/collection.", + " S collectInto One element to collect. Use [`map()`](#map) to transform into a list/collection.", + " C collectInto Always empty. Use [`andThen()`](#andThen) to bring in a collection.", + " MS combineLatest At most one element per source. Use [`zip()`](#zip).", + " C combineLatest Always empty. Use [`merge()`](#merge).", + " MS combineLatestArray At most one element per source. Use [`zipArray()`](#zipArray).", + " C combineLatestArray Always empty. Use [`mergeArray()`](#mergeArray).", + " MS combineLatestDelayError At most one element per source. Use [`zip()`](#zip).", + " C combineLatestDelayError Always empty. Use [`mergeDelayError()`](#mergeDelayError).", + " MS combineLatestArrayDelayError At most one element per source. Use [`zipArray()`](#zipArray).", + " C combineLatestArrayDelayError Always empty. Use [`mergeArrayDelayError()`](#mergeArrayDelayError).", + "FOM complete Use [`empty()`](#empty).", + " S complete Never empty.", + " C concatArrayEager No items to keep ordered. Use [`mergeArray()`](#mergeArray).", + " C concatArrayEagerDelayError No items to keep ordered. Use [`mergeArrayDelayError()`](#mergeArrayDelayError).", + " C concatEager No items to keep ordered. Use [`merge()`](#merge).", + " C concatEagerDelayError No items to keep ordered. Use [`mergeDelayError()`](#mergeDelayError).", + " C concatMap Always empty thus no items to map.", + " C concatMapCompletable Always empty thus no items to map.", + " MS concatMapCompletableDelayError Either the upstream fails (thus no inner) or the mapped-in source, but never both. Use [`concatMapCompletable`](#concatMapCompletable).", + " C concatMapCompletableDelayError Always empty thus no items to map.", + " MS concatMapDelayError Either the upstream fails (thus no inner) or the mapped-in source, but never both. Use [`concatMap`](#concatMap).", + " C concatMapDelayError Always empty thus no items to map.", + " MS concatMapEager At most one item to map. Use [`concatMap()`](#concatMap).", + " C concatMapEager Always empty thus no items to map.", + " MS concatMapEagerDelayError At most one item to map. Use [`concatMap()`](#concatMap).", + " C concatMapEagerDelayError Always empty thus no items to map.", + " C concatMapIterable Always empty thus no items to map.", + " M concatMapMaybe Use [`concatMap`](#concatMap).", + " C concatMapMaybe Always empty thus no items to map.", + " MS concatMapMaybeDelayError Either the upstream fails (thus no inner) or the mapped-in source, but never both. Use [`concatMapMaybe`](#concatMapMaybe).", + " C concatMapMaybeDelayError Always empty thus no items to map.", + " S concatMapSingle Use [`concatMap()`](#concatMap).", + " C concatMapSingle Always empty thus no items to map.", + " MS concatMapSingleDelayError Either the upstream fails (thus no inner) or the mapped-in source, but never both. Use [`concatMapSingle`](#concatMapSingle).", + " C concatMapSingleDelayError Always empty thus no items to map.", + " C concatMapStream Always empty thus no items to map.", + " MS concatMapIterable At most one item. Use [`flattenAsFlowable`](#flattenAsFlowable) or [`flattenAsObservable`](#flattenAsObservable).", + " MS concatMapStream At most one item. Use [`flattenStreamAsFlowable`](#flattenStreamAsFlowable) or [`flattenStreamAsObservable`](#flattenStreamAsObservable).", + " C contains Always empty.", + " S count Never empty thus always 1.", + " C count Always empty thus always 0.", + " MS debounce At most one item signaled so no subsequent items to work with.", + " C debounce Always empty thus no items to work with.", + " S defaultIfEmpty Never empty.", + " C defaultIfEmpty Always empty. Use [`andThen()`](#andThen) to chose the follow-up sequence.", + " C dematerialize Always empty thus no items to work with.", + " MS distinct At most one item, always distinct.", + " C distinct Always empty thus no items to work with.", + " MS distinctUntilChanged At most one item, always distinct.", + " C distinctUntilChanged Always empty thus no items to work with.", + " MS doAfterNext Different terminology. Use [`doAfterSuccess()`](#doAfterSuccess).", + " C doAfterNext Always empty.", + "FO doAfterSuccess Different terminology. Use [`doAfterNext()`](#doAfterNext).", + " C doAfterSuccess Always empty thus no items to work with.", + " OMSC doOnCancel Different terminology. Use [`doOnDispose()`](#doOnDispose).", + " S doOnComplete Always succeeds or fails, there is no `onComplete` signal.", + "F doOnDispose Different terminology. Use [`doOnCancel()`](#doOnCancel).", + " MS doOnEach At most one item. Use [`doOnEvent()`](#doOnEvent).", + " C doOnEach Always empty thus no items to work with.", + "FO doOnEvent Use [`doOnEach()`](#doOnEach).", + " MS doOnNext Different terminology. Use [`doOnSuccess()`](#doOnSuccess).", + " C doOnNext Always empty thus no items to work with.", + " OMSC doOnRequest Backpressure related and not supported outside `Flowable`.", + "FO doOnSuccess Different terminology. Use [`doOnNext()`](#doOnNext).", + " C doOnSuccess Always empty thus no items to work with.", + " M elementAt At most one item with index 0. Use [`defaultIfEmpty`](#defaultIfEmpty).", + " S elementAt Always one item with index 0.", + " C elementAt Always empty thus no items to work with.", + " M elementAtOrError At most one item with index 0. Use [`toSingle`](#toSingle).", + " S elementAtOrError Always one item with index 0.", + " C elementAtOrError Always empty thus no items to work with.", + " S empty Never empty.", + " C empty Use [`complete()`](#complete).", + " C filter Always empty thus no items to work with.", + " M first At most one item. Use [`defaultIfEmpty`](#defaultIfEmpty).", + " S first Always one item.", + " C first Always empty. Use [`andThen()`](#andThen) to chose the follow-up sequence.", + " M firstElement At most one item, would be no-op.", + " S firstElement Always one item, would be no-op.", + " C firstElement Always empty.", + " M firstOrError At most one item, would be no-op.", + " S firstOrError Always one item, would be no-op.", + " C firstOrError Always empty. Use [`andThen()`](#andThen) and [`error()`](#error).", + " MS firstOrErrorStage At most one item. Use [`toCompletionStage()`](#toCompletionStage).", + " C firstOrErrorStage Always empty. Use [`andThen()`](#andThen), [`error()`](#error) and [`toCompletionStage()`](#toCompletionStage).", + " MSC firstStage At most one item. Use [`toCompletionStage()`](#toCompletionStage).", + " C flatMap Always empty thus no items to map.", + " C flatMapCompletable Always empty thus no items to map.", + " C flatMapCompletableDelayError Always empty thus no items to map.", + " C flatMapIterable Always empty thus no items to map.", + " M flatMapMaybe Use [`flatMap()`](#flatMap).", + " C flatMapMaybe Always empty thus no items to map.", + " C flatMapMaybeDelayError Always empty thus no items to map.", + " S flatMapSingle Use [`flatMap()`](#flatMap).", + " C flatMapSingle Always empty thus no items to map.", + " C flatMapStream Always empty thus no items to map.", + " MS flatMapIterable At most one item. Use [`flattenAsFlowable`](#flattenAsFlowable) or [`flattenAsObservable`](#flattenAsObservable).", + " MS flatMapStream At most one item. Use [`flattenStreamAsFlowable`](#flattenStreamAsFlowable) or [`flattenStreamAsObservable`](#flattenStreamAsObservable).", + "F flatMapObservable Not supported. Use [`flatMap`](#flatMap) and [`toFlowable()`](#toFlowable).", + " O flatMapObservable Use [`flatMap`](#flatMap).", + " C flatMapObservable Always empty thus no items to map.", + " O flatMapPublisher Not supported. Use [`flatMap`](#flatMap) and [`toObservable()`](#toFlowable).", + "F flatMapPublisher Use [`flatMap`](#flatMap).", + " C flatMapPublisher Always empty thus no items to map.", + "FO flatMapSingleElement Use [`flatMapSingle`](#flatMapSingle).", + " S flatMapSingleElement Use [`flatMap`](#flatMap).", + " C flatMapSingleElement Always empty thus no items to map.", + "FO flattenAsFlowable Use [`flatMapIterable()`](#flatMapIterable).", + " C flattenAsFlowable Always empty thus no items to map.", + "FO flattenAsObservable Use [`flatMapIterable()`](#flatMapIterable).", + " C flattenAsObservable Always empty thus no items to map.", + "FO flattenStreamAsFlowable Use [`flatMapStream()`](#flatMapStream).", + " C flattenStreamAsFlowable Always empty thus no items to map.", + "FO flattenStreamAsObservable Use [`flatMapStream()`](#flatMapStream).", + " C flattenStreamAsObservable Always empty thus no items to map.", + " MSC forEach Use [`subscribe()`](#subscribe).", + " MSC forEachWhile Use [`subscribe()`](#subscribe).", + " S fromAction Never empty.", + " M fromArray At most one item. Use [`just()`](#just) or [`empty()`](#empty).", + " S fromArray Always one item. Use [`just()`](#just).", + " C fromArray Always empty. Use [`complete()`](#complete).", + " S fromCompletable Always error.", + " C fromCompletable Use [`wrap()`](#wrap).", + " M fromIterable At most one item. Use [`just()`](#just) or [`empty()`](#empty).", + " S fromIterable Always one item. Use [`just()`](#just).", + " C fromIterable Always empty. Use [`complete()`](#complete).", + " M fromMaybe Use [`wrap()`](#wrap).", + " O fromObservable Use [`wrap()`](#wrap).", + " S fromOptional Always one item. Use [`just()`](#just).", + " C fromOptional Always empty. Use [`complete()`](#complete).", + " S fromRunnable Never empty.", + " S fromSingle Use [`wrap()`](#wrap).", + " M fromStream At most one item. Use [`just()`](#just) or [`empty()`](#empty).", + " S fromStream Always one item. Use [`just()`](#just).", + " C fromStream Always empty. Use [`complete()`](#complete).", + " MSC generate Use [`fromSupplier()`](#fromSupplier).", + " MS groupBy At most one item.", + " C groupBy Always empty thus no items to group.", + " MS groupJoin At most one item.", + " C groupJoin Always empty thus no items to join.", + "FO ignoreElement Use [`ignoreElements()`](#ignoreElements).", + " C ignoreElement Always empty.", + " MS ignoreElements Use [`ignoreElement()`](#ignoreElement).", + " C ignoreElements Always empty.", + " MSC interval At most one item. Use [`timer()`](#timer).", + " MSC intervalRange At most one item. Use [`timer()`](#timer).", + " S isEmpty Always one item.", + " C isEmpty Always empty.", + " MS join At most one item. Use [`zip()`](#zip)", + " C join Always empty thus no items to join.", + " C just Always empty.", + " M last At most one item. Use [`defaultIfEmpty`](#defaultIfEmpty).", + " S last Always one item.", + " C last Always empty. Use [`andThen()`](#andThen) to chose the follow-up sequence.", + " M lastElement At most one item, would be no-op.", + " S lastElement Always one item, would be no-op.", + " C lastElement Always empty.", + " M lastOrError At most one item, would be no-op.", + " S lastOrError Always one item, would be no-op.", + " C lastOrError Always empty. Use [`andThen()`](#andThen) and [`error()`](#error).", + " MS lastOrErrorStage At most one item. Use [`toCompletionStage()`](#toCompletionStage).", + " C lastOrErrorStage Always empty. Use [`andThen()`](#andThen), [`error()`](#error) and [`toCompletionStage()`](#toCompletionStage).", + " MSC lastStage At most one item. Use [`toCompletionStage()`](#toCompletionStage).", + " C map Always empty thus no items to map.", + " C mapOptional Always empty thus no items to map.", + " C ofType Always empty thus no items to filter.", + " OMSC onBackpressureBuffer Backpressure related and not supported outside `Flowable`.", + " OMSC onBackpressureDrop Backpressure related and not supported outside `Flowable`.", + " OMSC onBackpressureLatest Backpressure related and not supported outside `Flowable`.", + " OMSC parallel Needs backpressure thus not supported outside `Flowable`.", + " M publish Connectable sources not supported outside `Flowable` and `Observable`. Use a `MaybeSubject`.", + " S publish Connectable sources not supported outside `Flowable` and `Observable`. Use a `SingleSubject`.", + " C publish Connectable sources not supported outside `Flowable` and `Observable`. Use a `ConnectableSubject`.", + " MS range At most one item. Use [`just()`](#just).", + " C range Always empty. Use [`complete()`](#complete).", + " MS rangeLong At most one item. Use [`just()`](#just).", + " C rangeLong Always empty. Use [`complete()`](#complete).", + " OMSC rebatchRequests Backpressure related and not supported outside `Flowable`.", + " MS reduce At most one item. Use [`map()`](#map).", + " C reduce Always empty thus no items to reduce.", + " MS reduceWith At most one item. Use [`map()`](#map).", + " C reduceWith Always empty thus no items to reduce.", + " M replay Connectable sources not supported outside `Flowable` and `Observable`. Use a `MaybeSubject`.", + " S replay Connectable sources not supported outside `Flowable` and `Observable`. Use a `SingleSubject`.", + " C replay Connectable sources not supported outside `Flowable` and `Observable`. Use a `ConnectableSubject`.", + " MS sample At most one item, would be no-op.", + " C sample Always empty thus no items to work with.", + " MS scan At most one item. Use [`map()`](#map).", + " C scan Always empty thus no items to reduce.", + " MS scanWith At most one item. Use [`map()`](#map).", + " C scanWith Always empty thus no items to reduce.", + " MSC serialize At most one signal type.", + " M share Connectable sources not supported outside `Flowable` and `Observable`. Use a `MaybeSubject`.", + " S share Connectable sources not supported outside `Flowable` and `Observable`. Use a `SingleSubject`.", + " C share Connectable sources not supported outside `Flowable` and `Observable`. Use a `ConnectableSubject`.", + " M single At most one item. Use [`defaultIfEmpty`](#defaultIfEmpty).", + " S single Always one item.", + " C single Always empty. Use [`andThen()`](#andThen) to chose the follow-up sequence.", + " M singleElement At most one item, would be no-op.", + " S singleElement Always one item, would be no-op.", + " C singleElement Always empty.", + " M singleOrError At most one item, would be no-op.", + " S singleOrError Always one item, would be no-op.", + " C singleOrError Always empty. Use [`andThen()`](#andThen) and [`error()`](#error).", + " MS singleOrErrorStage At most one item. Use [`toCompletionStage()`](#toCompletionStage).", + " C singleOrErrorStage Always empty. Use [`andThen()`](#andThen), [`error()`](#error) and [`toCompletionStage()`](#toCompletionStage).", + " MSC singleStage At most one item. Use [`toCompletionStage()`](#toCompletionStage).", + " MSC skip At most one item, would be no-op.", + " MSC skipLast At most one item, would be no-op.", + " MS skipWhile At most one item. Use [`filter()`](#filter).", + " C skipWhile Always empty.", + " MSC skipUntil At most one item. Use [`takeUntil()`](#takeUntil).", + " MSC sorted At most one item.", + " MSC startWithArray Use [`startWith()`](#startWith) and [`fromArray()`](#fromArray) of `Flowable` or `Observable`.", + " MSC startWithItem Use [`startWith()`](#startWith) and [`just()`](#just) of another reactive type.", + " MSC startWithIterable Use [`startWith()`](#startWith) and [`fromIterable()`](#fromArray) of `Flowable` or `Observable`.", + " S switchIfEmpty Never empty.", + " C switchIfEmpty Always empty. Use [`defaultIfEmpty()`](#defaultIfEmpty).", + " MS switchMap At most one item. Use [`flatMap()`](#flatMap).", + " C switchMap Always empty thus no items to map.", + " MS switchMapDelayError At most one item. Use [`flatMap()`](#flatMap).", + " C switchMapDelayError Always empty thus no items to map.", + " MS switchMapCompletable At most one item. Use [`flatMap()`](#flatMap).", + " C switchMapCompletable Always empty thus no items to map.", + " MS switchMapCompletableDelayError At most one item. Use [`flatMap()`](#flatMap).", + " C switchMapCompletableDelayError Always empty thus no items to map.", + " MS switchMapMaybe At most one item. Use [`flatMap()`](#flatMap).", + " C switchMapMaybe Always empty thus no items to map.", + " MS switchMapMaybeDelayError At most one item. Use [`flatMap()`](#flatMap).", + " C switchMapMaybeDelayError Always empty thus no items to map.", + " MS switchMapSingle At most one item. Use [`flatMap()`](#flatMap).", + " C switchMapSingle Always empty thus no items to map.", + " MS switchMapSingleDelayError At most one item. Use [`flatMap()`](#flatMap).", + " C switchMapSingleDelayError Always empty thus no items to map.", + " MSC take At most one item, would be no-op.", + " MSC takeLast At most one item, would be no-op.", + " MS takeWhile At most one item. Use [`filter()`](#filter).", + " C takeWhile Always empty.", + " MS throttleFirst At most one item signaled so no subsequent items to work with.", + " C throttleFirst Always empty thus no items to work with.", + " MS throttleLast At most one item signaled so no subsequent items to work with.", + " C throttleLast Always empty thus no items to work with.", + " MS throttleLatest At most one item signaled so no subsequent items to work with.", + " C throttleLatest Always empty thus no items to work with.", + " MS throttleWithTimeout At most one item signaled so no subsequent items to work with.", + " C throttleWithTimeout Always empty thus no items to work with.", + " C timeInterval Always empty thus no items to work with.", + " C timestamp Always empty thus no items to work with.", + "FO toCompletionStage Use [`firstStage`](#firstStage), [`lastStage`](#lastStage) or [`singleStage`](#singleStage).", + "F toFlowable Would be no-op.", + " M toList At most one element to collect. Use [`map()`](#map) and [`switchIfEmpty()`](#switchIfEmpty) to transform into a list/collection.", + " S toList One element to collect. Use [`map()`](#map) to transform into a list/collection.", + " C toList Always empty. Use [`andThen()`](#andThen) to bring in a collection.", + " M toMap At most one element to collect. Use [`map()`](#map) and [`switchIfEmpty()`](#switchIfEmpty) to transform into a list/collection.", + " S toMap One element to collect. Use [`map()`](#map) to transform into a list/collection.", + " C toMap Always empty. Use [`andThen()`](#andThen) to bring in a collection.", + " M toMultimap At most one element to collect. Use [`map()`](#map) and [`switchIfEmpty()`](#switchIfEmpty) to transform into a list/collection.", + " S toMultimap One element to collect. Use [`map()`](#map) to transform into a list/collection.", + " C toMultimap Always empty. Use [`andThen()`](#andThen) to bring in a collection.", + "FO toMaybe Use [`firstElement`](#firstElement), [`lastElement`](#lastElement) or [`singleElement`](#singleElement).", + " M toMaybe Would be no-op.", + " O toObservable Would be no-op.", + "FO toSingle Use [`firstOrError`](#firstOrError), [`lastOrError`](#lastOrError) or [`singleOrError`](#singleOrError).", + " S toSingle Would be no-op.", + "FO toSingleDefault Use [`first`](#first), [`last`](#last) or [`single`](#single).", + " M toSingleDefault Use [`defaultIfEmpty()`](#defaultIfEmpty).", + " S toSingleDefault Would be no-op.", + " M toSortedList At most one element to collect. Use [`map()`](#map) and [`switchIfEmpty()`](#switchIfEmpty) to transform into a list/collection.", + " S toSortedList One element to collect. Use [`map()`](#map) to transform into a list/collection.", + " C toSortedList Always empty. Use [`andThen()`](#andThen) to bring in a collection.", + " M window Use [`map()`](#map) and [`switchIfEmpty()`](#switchIfEmpty) to transform into a nested source.", + " S window Use [`map()`](#map) to transform into a nested source.", + " C window Always empty. Use [`andThen()`](#andThen) to bring in a nested source.", + " MS withLatestFrom At most one element per source. Use [`zip()`](#zip).", + " C withLatestFrom Always empty. Use [`merge()`](#merge).", + "F wrap Use [`fromPublisher()`](#fromPublisher).", + " C zip Use [`merge()`](#merge).", + " C zipArray Use [`mergeArray()`](#mergeArray).", + " C zipWith Use [`mergeWith()`](#mergeWith).", + }; + + static final Map> NOTES_MAP; + static { + NOTES_MAP = new HashMap<>(); + for (String s : NOTES) { + char[] classes = s.substring(0, 5).trim().toCharArray(); + int idx = s.indexOf(' ', 7); + String method = s.substring(6, idx); + String note = s.substring(idx).trim(); + + for (char c : classes) { + NOTES_MAP.computeIfAbsent(method, v -> new HashMap<>()) + .put(String.valueOf(c), note); + } + } + } +} diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/QueueDrainHelperTest.java b/src/test/java/io/reactivex/rxjava3/internal/util/QueueDrainHelperTest.java index 5fac86182a5..7929ea8782b 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/QueueDrainHelperTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/QueueDrainHelperTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,9 +27,9 @@ import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.BooleanSupplier; -import io.reactivex.rxjava3.internal.queue.SpscArrayQueue; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.SpscArrayQueue; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.TestHelper; diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/TestingHelper.java b/src/test/java/io/reactivex/rxjava3/internal/util/TestingHelper.java index 976757acd78..207c85236d6 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/TestingHelper.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/TestingHelper.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.internal.util; import java.util.*; diff --git a/src/test/java/io/reactivex/rxjava3/internal/util/VolatileSizeArrayListTest.java b/src/test/java/io/reactivex/rxjava3/internal/util/VolatileSizeArrayListTest.java index c59537c988b..3ce08aa3dc8 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/util/VolatileSizeArrayListTest.java +++ b/src/test/java/io/reactivex/rxjava3/internal/util/VolatileSizeArrayListTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/maybe/MaybeCreateTest.java b/src/test/java/io/reactivex/rxjava3/maybe/MaybeCreateTest.java index ee97e250157..e3bbfb4bfc1 100644 --- a/src/test/java/io/reactivex/rxjava3/maybe/MaybeCreateTest.java +++ b/src/test/java/io/reactivex/rxjava3/maybe/MaybeCreateTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,11 +27,6 @@ import io.reactivex.rxjava3.testsupport.TestHelper; public class MaybeCreateTest extends RxJavaTest { - @Test(expected = NullPointerException.class) - public void nullArgument() { - Maybe.create(null); - } - @Test public void basic() { List errors = TestHelper.trackPluginErrors(); diff --git a/src/test/java/io/reactivex/rxjava3/maybe/MaybeRetryTest.java b/src/test/java/io/reactivex/rxjava3/maybe/MaybeRetryTest.java index f260a78a82a..731dd03e23b 100644 --- a/src/test/java/io/reactivex/rxjava3/maybe/MaybeRetryTest.java +++ b/src/test/java/io/reactivex/rxjava3/maybe/MaybeRetryTest.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2017-present, RxJava Contributors. +/* + * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at @@ -21,6 +21,7 @@ import org.junit.Test; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Predicate; import io.reactivex.rxjava3.internal.functions.Functions; @@ -120,4 +121,58 @@ public void retryTimesPredicateWithZeroRetries() { assertEquals(1, numberOfSubscribeCalls.get()); } + + @Test + public void untilTrueJust() { + Maybe.just(1) + .retryUntil(() -> true) + .test() + .assertResult(1); + } + + @Test + public void untilFalseJust() { + Maybe.just(1) + .retryUntil(() -> false) + .test() + .assertResult(1); + } + + @Test + public void untilTrueEmpty() { + Maybe.empty() + .retryUntil(() -> true) + .test() + .assertResult(); + } + + @Test + public void untilFalseEmpty() { + Maybe.empty() + .retryUntil(() -> false) + .test() + .assertResult(); + } + + @Test + public void untilTrueError() { + Maybe.error(new TestException()) + .retryUntil(() -> true) + .test() + .assertFailure(TestException.class); + } + + @Test + public void untilFalseError() { + AtomicInteger counter = new AtomicInteger(); + Maybe.defer(() -> { + if (counter.getAndIncrement() == 0) { + return Maybe.error(new TestException()); + } + return Maybe.just(1); + }) + .retryUntil(() -> false) + .test() + .assertResult(1); + } } diff --git a/src/test/java/io/reactivex/rxjava3/maybe/MaybeTest.java b/src/test/java/io/reactivex/rxjava3/maybe/MaybeTest.java index b5a03ede3bd..acc7066c292 100644 --- a/src/test/java/io/reactivex/rxjava3/maybe/MaybeTest.java +++ b/src/test/java/io/reactivex/rxjava3/maybe/MaybeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,10 +30,10 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.internal.operators.flowable.FlowableZipTest.ArgsToString; import io.reactivex.rxjava3.internal.operators.maybe.*; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.schedulers.Schedulers; @@ -172,11 +172,6 @@ public void just() { .assertResult(1); } - @Test(expected = NullPointerException.class) - public void justNull() { - Maybe.just(null); - } - @Test public void empty() { Maybe.empty() @@ -194,16 +189,6 @@ public void never() { .assertNotComplete(); } - @Test(expected = NullPointerException.class) - public void errorNull() { - Maybe.error((Throwable)null); - } - - @Test(expected = NullPointerException.class) - public void errorSupplierNull() { - Maybe.error((Supplier)null); - } - @Test public void error() { Maybe.error(new TestException()) @@ -243,11 +228,6 @@ public void wrapMaybe() { assertSame(Maybe.empty(), Maybe.wrap(Maybe.empty())); } - @Test(expected = NullPointerException.class) - public void wrapNull() { - Maybe.wrap(null); - } - @Test public void emptySingleton() { assertSame(Maybe.empty(), Maybe.empty()); @@ -258,11 +238,6 @@ public void neverSingleton() { assertSame(Maybe.never(), Maybe.never()); } - @Test(expected = NullPointerException.class) - public void liftNull() { - Maybe.just(1).lift(null); - } - @Test public void liftJust() { Maybe.just(1).lift(new MaybeOperator() { @@ -287,11 +262,6 @@ public MaybeObserver apply(MaybeObserver t) th .assertFailure(TestException.class); } - @Test(expected = NullPointerException.class) - public void deferNull() { - Maybe.defer(null); - } - @Test public void deferThrows() { Maybe.defer(new Supplier>() { @@ -364,11 +334,6 @@ public void subscribe(MaybeObserver observer) { .assertResult(1); } - @Test(expected = NullPointerException.class) - public void unsafeCreateNull() { - Maybe.unsafeCreate(null); - } - @Test public void to() { Maybe.just(1).to(new MaybeConverter>() { @@ -393,16 +358,6 @@ public Flowable apply(Maybe v) { .assertResult(1); } - @Test(expected = NullPointerException.class) - public void toNull() { - Maybe.just(1).to(null); - } - - @Test(expected = NullPointerException.class) - public void asNull() { - Maybe.just(1).to(null); - } - @Test public void compose() { Maybe.just(1).compose(new MaybeTransformer() { @@ -420,16 +375,6 @@ public Integer apply(Integer w) throws Exception { .assertResult(2); } - @Test(expected = NullPointerException.class) - public void composeNull() { - Maybe.just(1).compose(null); - } - - @Test(expected = NullPointerException.class) - public void mapNull() { - Maybe.just(1).map(null); - } - @Test public void mapReturnNull() { Maybe.just(1).map(new Function() { @@ -460,11 +405,6 @@ public String apply(Integer v) throws Exception { }).test().assertResult("1"); } - @Test(expected = NullPointerException.class) - public void filterNull() { - Maybe.just(1).filter(null); - } - @Test public void filterThrows() { Maybe.just(1).filter(new Predicate() { @@ -505,11 +445,6 @@ public boolean test(Integer v) throws Exception { }).test().assertResult(); } - @Test(expected = NullPointerException.class) - public void singleFilterNull() { - Single.just(1).filter(null); - } - @Test public void singleFilterThrows() { Single.just(1).filter(new Predicate() { @@ -547,16 +482,6 @@ public void cast() { to.assertResult((Number)1); } - @Test(expected = NullPointerException.class) - public void observeOnNull() { - Maybe.just(1).observeOn(null); - } - - @Test(expected = NullPointerException.class) - public void subscribeOnNull() { - Maybe.just(1).observeOn(null); - } - @Test public void observeOnSuccess() { String main = Thread.currentThread().getName(); @@ -1488,11 +1413,6 @@ public void concatPublisherPrefetch() { Maybe.concat(Flowable.just(Maybe.just(1), Maybe.just(2)), 1).test().assertResult(1, 2); } - @Test(expected = NullPointerException.class) - public void nullArgument() { - Maybe.create(null); - } - @Test public void basic() { List errors = TestHelper.trackPluginErrors(); @@ -1928,11 +1848,6 @@ public void ambIterable2SignalsComplete() { to.assertResult(); } - @Test(expected = NullPointerException.class) - public void ambIterableNull() { - Maybe.amb((Iterable>)null); - } - @Test public void ambIterableIteratorNull() { Maybe.amb(new Iterable>() { @@ -2392,11 +2307,6 @@ public void accept(Integer v, Throwable e) throws Exception { assertEquals(Arrays.asList(null, null), list); } - @Test(expected = NullPointerException.class) - public void doOnEventNull() { - Maybe.just(1).doOnEvent(null); - } - @Test public void doOnEventSuccessThrows() { Maybe.just(1) @@ -2478,6 +2388,17 @@ public void concatPublisherDelayError() { .assertFailure(TestException.class, 1); } + @Test + public void concatPublisherDelayErrorPrefetch() { + Maybe.concatDelayError(Flowable.just(Maybe.empty(), Maybe.just(1), Maybe.error(new TestException())), 1) + .test() + .assertFailure(TestException.class, 1); + + Maybe.concatDelayError(Flowable.just(Maybe.error(new TestException()), Maybe.empty(), Maybe.just(1)), 1) + .test() + .assertFailure(TestException.class, 1); + } + @Test public void concatEagerArray() { PublishProcessor pp1 = PublishProcessor.create(); @@ -2593,8 +2514,6 @@ public void mergeArrayDelayError() { Maybe.mergeArrayDelayError(Maybe.error(new TestException()), Maybe.empty(), Maybe.just(1)) .test() .assertFailure(TestException.class, 1); - - assertSame(Flowable.empty(), Maybe.mergeArrayDelayError()); } @Test diff --git a/src/test/java/io/reactivex/rxjava3/maybe/MaybeTimerTest.java b/src/test/java/io/reactivex/rxjava3/maybe/MaybeTimerTest.java index 03f229483be..286639042df 100644 --- a/src/test/java/io/reactivex/rxjava3/maybe/MaybeTimerTest.java +++ b/src/test/java/io/reactivex/rxjava3/maybe/MaybeTimerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableCombineLatestTests.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableCombineLatestTests.java index b4b11420d12..957268ecf19 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableCombineLatestTests.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableCombineLatestTests.java @@ -1,18 +1,16 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.observable; import org.junit.Test; diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableConcatTests.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableConcatTests.java index f867a165d2c..53c4f990297 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableConcatTests.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableConcatTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.observable; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableCovarianceTest.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableCovarianceTest.java index e7e3302fd81..54cf0f9908f 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableCovarianceTest.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableCovarianceTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.observable; diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableDoOnTest.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableDoOnTest.java index 6c3b5f54ab5..0e7ed9ef889 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableDoOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableDoOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableErrorHandlingTests.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableErrorHandlingTests.java index c524261032e..9ec13895b01 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableErrorHandlingTests.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableErrorHandlingTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableEventStream.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableEventStream.java index 6b161dcb0ac..48e637f5c3a 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableEventStream.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableEventStream.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableFuseableTest.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableFuseableTest.java index 1d01a790ab2..8de9b9bc0bb 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableFuseableTest.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableFuseableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.observable; import java.util.Arrays; @@ -17,7 +18,7 @@ import org.junit.Test; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.testsupport.TestHelper; public class ObservableFuseableTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableGroupByTests.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableGroupByTests.java index e5de6cdc85c..1db6ebb9088 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableGroupByTests.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableGroupByTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableMergeTests.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableMergeTests.java index 902bcd7ba1c..25a3317b7fe 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableMergeTests.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableMergeTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableNullTests.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableNullTests.java index 0fa7c22711c..178adb62306 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableNullTests.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableNullTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,7 +22,6 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; -import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; @@ -40,21 +39,6 @@ public class ObservableNullTests extends RxJavaTest { // Static methods //*********************************************************** - @Test(expected = NullPointerException.class) - public void ambVarargsNull() { - Observable.ambArray((Observable[])null); - } - - @Test(expected = NullPointerException.class) - public void ambVarargsOneIsNull() { - Observable.ambArray(Observable.never(), null).blockingLast(); - } - - @Test(expected = NullPointerException.class) - public void ambIterableNull() { - Observable.amb((Iterable>)null); - } - @Test public void ambIterableIteratorNull() { Observable.amb(new Iterable>() { @@ -72,16 +56,6 @@ public void ambIterableOneIsNull() { .assertError(NullPointerException.class); } - @Test(expected = NullPointerException.class) - public void combineLatestIterableNull() { - Observable.combineLatest((Iterable>)null, new Function() { - @Override - public Object apply(Object[] v) { - return 1; - } - }, 128); - } - @Test(expected = NullPointerException.class) public void combineLatestIterableIteratorNull() { Observable.combineLatest(new Iterable>() { @@ -107,11 +81,6 @@ public Object apply(Object[] v) { }, 128).blockingLast(); } - @Test(expected = NullPointerException.class) - public void combineLatestIterableFunctionNull() { - Observable.combineLatest(Arrays.asList(just1), null, 128); - } - @Test(expected = NullPointerException.class) public void combineLatestIterableFunctionReturnsNull() { Observable.combineLatest(Arrays.asList(just1), new Function() { @@ -122,16 +91,6 @@ public Object apply(Object[] v) { }, 128).blockingLast(); } - @Test(expected = NullPointerException.class) - public void combineLatestDelayErrorIterableNull() { - Observable.combineLatestDelayError((Iterable>)null, new Function() { - @Override - public Object apply(Object[] v) { - return 1; - } - }, 128); - } - @Test(expected = NullPointerException.class) public void combineLatestDelayErrorIterableIteratorNull() { Observable.combineLatestDelayError(new Iterable>() { @@ -157,11 +116,6 @@ public Object apply(Object[] v) { }, 128).blockingLast(); } - @Test(expected = NullPointerException.class) - public void combineLatestDelayErrorIterableFunctionNull() { - Observable.combineLatestDelayError(Arrays.asList(just1), null, 128); - } - @Test(expected = NullPointerException.class) public void combineLatestDelayErrorIterableFunctionReturnsNull() { Observable.combineLatestDelayError(Arrays.asList(just1), new Function() { @@ -172,11 +126,6 @@ public Object apply(Object[] v) { }, 128).blockingLast(); } - @Test(expected = NullPointerException.class) - public void concatIterableNull() { - Observable.concat((Iterable>)null); - } - @Test(expected = NullPointerException.class) public void concatIterableIteratorNull() { Observable.concat(new Iterable>() { @@ -192,31 +141,11 @@ public void concatIterableOneIsNull() { Observable.concat(Arrays.asList(just1, null)).blockingLast(); } - @Test(expected = NullPointerException.class) - public void concatObservableNull() { - Observable.concat((Observable>)null); - } - - @Test(expected = NullPointerException.class) - public void concatArrayNull() { - Observable.concatArray((Observable[])null); - } - @Test(expected = NullPointerException.class) public void concatArrayOneIsNull() { Observable.concatArray(just1, null).blockingLast(); } - @Test(expected = NullPointerException.class) - public void createNull() { - Observable.unsafeCreate(null); - } - - @Test(expected = NullPointerException.class) - public void deferFunctionNull() { - Observable.defer(null); - } - @Test(expected = NullPointerException.class) public void deferFunctionReturnsNull() { Observable.defer(new Supplier>() { @@ -227,11 +156,6 @@ public Observable get() { }).blockingLast(); } - @Test(expected = NullPointerException.class) - public void errorFunctionNull() { - Observable.error((Supplier)null); - } - @Test(expected = NullPointerException.class) public void errorFunctionReturnsNull() { Observable.error(new Supplier() { @@ -242,26 +166,11 @@ public Throwable get() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void errorThrowableNull() { - Observable.error((Throwable)null); - } - - @Test(expected = NullPointerException.class) - public void fromArrayNull() { - Observable.fromArray((Object[])null); - } - @Test(expected = NullPointerException.class) public void fromArrayOneIsNull() { Observable.fromArray(1, null).blockingLast(); } - @Test(expected = NullPointerException.class) - public void fromCallableNull() { - Observable.fromCallable(null); - } - @Test(expected = NullPointerException.class) public void fromCallableReturnsNull() { Observable.fromCallable(new Callable() { @@ -272,11 +181,6 @@ public Object call() throws Exception { }).blockingLast(); } - @Test(expected = NullPointerException.class) - public void fromFutureNull() { - Observable.fromFuture(null); - } - @Test public void fromFutureReturnsNull() { FutureTask f = new FutureTask<>(Functions.EMPTY_RUNNABLE, null); @@ -289,21 +193,6 @@ public void fromFutureReturnsNull() { to.assertError(NullPointerException.class); } - @Test(expected = NullPointerException.class) - public void fromFutureTimedFutureNull() { - Observable.fromFuture(null, 1, TimeUnit.SECONDS); - } - - @Test(expected = NullPointerException.class) - public void fromFutureTimedUnitNull() { - Observable.fromFuture(new FutureTask<>(Functions.EMPTY_RUNNABLE, null), 1, null); - } - - @Test(expected = NullPointerException.class) - public void fromFutureTimedSchedulerNull() { - Observable.fromFuture(new FutureTask<>(Functions.EMPTY_RUNNABLE, null), 1, TimeUnit.SECONDS, null); - } - @Test(expected = NullPointerException.class) public void fromFutureTimedReturnsNull() { FutureTask f = new FutureTask<>(Functions.EMPTY_RUNNABLE, null); @@ -311,17 +200,6 @@ public void fromFutureTimedReturnsNull() { Observable.fromFuture(f, 1, TimeUnit.SECONDS).blockingLast(); } - @Test(expected = NullPointerException.class) - public void fromFutureSchedulerNull() { - FutureTask f = new FutureTask<>(Functions.EMPTY_RUNNABLE, null); - Observable.fromFuture(f, null); - } - - @Test(expected = NullPointerException.class) - public void fromIterableNull() { - Observable.fromIterable(null); - } - @Test(expected = NullPointerException.class) public void fromIterableIteratorNull() { Observable.fromIterable(new Iterable() { @@ -337,11 +215,6 @@ public void fromIterableValueNull() { Observable.fromIterable(Arrays.asList(1, null)).blockingLast(); } - @Test(expected = NullPointerException.class) - public void generateConsumerNull() { - Observable.generate(null); - } - @Test(expected = NullPointerException.class) public void generateConsumerEmitsNull() { Observable.generate(new Consumer>() { @@ -352,35 +225,6 @@ public void accept(Emitter s) { }).blockingLast(); } - @Test(expected = NullPointerException.class) - public void generateStateConsumerInitialStateNull() { - BiConsumer> generator = new BiConsumer>() { - @Override - public void accept(Integer s, Emitter o) { - o.onNext(1); - } - }; - Observable.generate(null, generator); - } - - @Test(expected = NullPointerException.class) - public void generateStateFunctionInitialStateNull() { - Observable.generate(null, new BiFunction, Object>() { - @Override - public Object apply(Object s, Emitter o) { o.onNext(1); return s; } - }); - } - - @Test(expected = NullPointerException.class) - public void generateStateConsumerNull() { - Observable.generate(new Supplier() { - @Override - public Integer get() { - return 1; - } - }, (BiConsumer>)null); - } - @Test public void generateConsumerStateNullAllowed() { BiConsumer> generator = new BiConsumer>() { @@ -410,64 +254,10 @@ public Object get() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void generateConsumerDisposeNull() { - BiConsumer> generator = new BiConsumer>() { - @Override - public void accept(Integer s, Emitter o) { - o.onNext(1); - } - }; - Observable.generate(new Supplier() { - @Override - public Integer get() { - return 1; - } - }, generator, null); - } - - @Test(expected = NullPointerException.class) - public void generateFunctionDisposeNull() { - Observable.generate(new Supplier() { - @Override - public Object get() { - return 1; - } - }, new BiFunction, Object>() { - @Override - public Object apply(Object s, Emitter o) { o.onNext(1); return s; } - }, null); - } - - @Test(expected = NullPointerException.class) - public void intervalUnitNull() { - Observable.interval(1, null); - } - public void intervalSchedulerNull() { Observable.interval(1, TimeUnit.SECONDS, null); } - @Test(expected = NullPointerException.class) - public void intervalPeriodUnitNull() { - Observable.interval(1, 1, null); - } - - @Test(expected = NullPointerException.class) - public void intervalPeriodSchedulerNull() { - Observable.interval(1, 1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void intervalRangeUnitNull() { - Observable.intervalRange(1, 1, 1, 1, null); - } - - @Test(expected = NullPointerException.class) - public void intervalRangeSchedulerNull() { - Observable.intervalRange(1, 1, 1, 1, TimeUnit.SECONDS, null); - } - @Test public void justNull() throws Exception { @SuppressWarnings("rawtypes") @@ -495,11 +285,6 @@ public void justNull() throws Exception { } } - @Test(expected = NullPointerException.class) - public void mergeIterableNull() { - Observable.merge((Iterable>)null, 128, 128); - } - @Test(expected = NullPointerException.class) public void mergeIterableIteratorNull() { Observable.merge(new Iterable>() { @@ -515,21 +300,6 @@ public void mergeIterableOneIsNull() { Observable.merge(Arrays.asList(just1, null), 128, 128).blockingLast(); } - @Test(expected = NullPointerException.class) - public void mergeArrayNull() { - Observable.mergeArray(128, 128, (Observable[])null); - } - - @Test(expected = NullPointerException.class) - public void mergeArrayOneIsNull() { - Observable.mergeArray(128, 128, just1, null).blockingLast(); - } - - @Test(expected = NullPointerException.class) - public void mergeDelayErrorIterableNull() { - Observable.mergeDelayError((Iterable>)null, 128, 128); - } - @Test(expected = NullPointerException.class) public void mergeDelayErrorIterableIteratorNull() { Observable.mergeDelayError(new Iterable>() { @@ -545,72 +315,6 @@ public void mergeDelayErrorIterableOneIsNull() { Observable.mergeDelayError(Arrays.asList(just1, null), 128, 128).blockingLast(); } - @Test(expected = NullPointerException.class) - public void mergeDelayErrorArrayNull() { - Observable.mergeArrayDelayError(128, 128, (Observable[])null); - } - - @Test(expected = NullPointerException.class) - public void mergeDelayErrorArrayOneIsNull() { - Observable.mergeArrayDelayError(128, 128, just1, null).blockingLast(); - } - - @Test(expected = NullPointerException.class) - public void sequenceEqualFirstNull() { - Observable.sequenceEqual(null, just1); - } - - @Test(expected = NullPointerException.class) - public void sequenceEqualSecondNull() { - Observable.sequenceEqual(just1, null); - } - - @Test(expected = NullPointerException.class) - public void sequenceEqualComparatorNull() { - Observable.sequenceEqual(just1, just1, null); - } - - @Test(expected = NullPointerException.class) - public void switchOnNextNull() { - Observable.switchOnNext(null); - } - - @Test(expected = NullPointerException.class) - public void timerUnitNull() { - Observable.timer(1, null); - } - - @Test(expected = NullPointerException.class) - public void timerSchedulerNull() { - Observable.timer(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void usingResourceSupplierNull() { - Observable.using(null, new Function>() { - @Override - public Observable apply(Object d) { - return just1; - } - }, new Consumer() { - @Override - public void accept(Object d) { } - }); - } - - @Test(expected = NullPointerException.class) - public void usingObservableSupplierNull() { - Observable.using(new Supplier() { - @Override - public Object get() { - return 1; - } - }, null, new Consumer() { - @Override - public void accept(Object d) { } - }); - } - @Test(expected = NullPointerException.class) public void usingObservableSupplierReturnsNull() { Observable.using(new Supplier() { @@ -629,31 +333,6 @@ public void accept(Object d) { } }).blockingLast(); } - @Test(expected = NullPointerException.class) - public void usingDisposeNull() { - Observable.using(new Supplier() { - @Override - public Object get() { - return 1; - } - }, new Function>() { - @Override - public Observable apply(Object d) { - return just1; - } - }, null); - } - - @Test(expected = NullPointerException.class) - public void zipIterableNull() { - Observable.zip((Iterable>)null, new Function() { - @Override - public Object apply(Object[] v) { - return 1; - } - }); - } - @Test(expected = NullPointerException.class) public void zipIterableIteratorNull() { Observable.zip(new Iterable>() { @@ -669,11 +348,6 @@ public Object apply(Object[] v) { }).blockingLast(); } - @Test(expected = NullPointerException.class) - public void zipIterableFunctionNull() { - Observable.zip(Arrays.asList(just1, just1), null); - } - @Test(expected = NullPointerException.class) public void zipIterableFunctionReturnsNull() { Observable.zip(Arrays.asList(just1, just1), new Function() { @@ -684,16 +358,6 @@ public Object apply(Object[] a) { }).blockingLast(); } - @Test(expected = NullPointerException.class) - public void zipIterable2Null() { - Observable.zip((Iterable>)null, new Function() { - @Override - public Object apply(Object[] a) { - return 1; - } - }, true, 128); - } - @Test(expected = NullPointerException.class) public void zipIterable2IteratorNull() { Observable.zip(new Iterable>() { @@ -709,11 +373,6 @@ public Object apply(Object[] a) { }, true, 128).blockingLast(); } - @Test(expected = NullPointerException.class) - public void zipIterable2FunctionNull() { - Observable.zip(Arrays.asList(just1, just1), null, true, 128); - } - @Test(expected = NullPointerException.class) public void zipIterable2FunctionReturnsNull() { Observable.zip(Arrays.asList(just1, just1), new Function() { @@ -728,26 +387,6 @@ public Object apply(Object[] a) { // Instance methods //************************************************************* - @Test(expected = NullPointerException.class) - public void allPredicateNull() { - just1.all(null); - } - - @Test(expected = NullPointerException.class) - public void ambWithNull() { - just1.ambWith(null); - } - - @Test(expected = NullPointerException.class) - public void anyPredicateNull() { - just1.any(null); - } - - @Test(expected = NullPointerException.class) - public void bufferSupplierNull() { - just1.buffer(1, 1, (Supplier>)null); - } - @Test(expected = NullPointerException.class) public void bufferSupplierReturnsNull() { just1.buffer(1, 1, new Supplier>() { @@ -758,21 +397,6 @@ public Collection get() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void bufferTimedUnitNull() { - just1.buffer(1L, 1L, null); - } - - @Test(expected = NullPointerException.class) - public void bufferTimedSchedulerNull() { - just1.buffer(1L, 1L, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void bufferTimedSupplierNull() { - just1.buffer(1L, 1L, TimeUnit.SECONDS, Schedulers.single(), null); - } - @Test(expected = NullPointerException.class) public void bufferTimedSupplierReturnsNull() { just1.buffer(1L, 1L, TimeUnit.SECONDS, Schedulers.single(), new Supplier>() { @@ -783,21 +407,6 @@ public Collection get() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void bufferOpenCloseOpenNull() { - just1.buffer(null, new Function>() { - @Override - public Observable apply(Object o) { - return just1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void bufferOpenCloseCloseNull() { - just1.buffer(just1, (Function>)null); - } - @Test(expected = NullPointerException.class) public void bufferOpenCloseCloseReturnsNull() { just1.buffer(just1, new Function>() { @@ -808,16 +417,6 @@ public Observable apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void bufferBoundaryNull() { - just1.buffer((Observable)null); - } - - @Test(expected = NullPointerException.class) - public void bufferBoundarySupplierNull() { - just1.buffer(just1, (Supplier>)null); - } - @Test(expected = NullPointerException.class) public void bufferBoundarySupplierReturnsNull() { just1.buffer(just1, new Supplier>() { @@ -828,19 +427,6 @@ public Collection get() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void castNull() { - just1.cast(null); - } - - @Test(expected = NullPointerException.class) - public void collectInitialSupplierNull() { - just1.collect((Supplier)null, new BiConsumer() { - @Override - public void accept(Integer a, Integer b) { } - }); - } - @Test(expected = NullPointerException.class) public void collectInitialSupplierReturnsNull() { just1.collect(new Supplier() { @@ -864,29 +450,6 @@ public Object get() { }, null); } - @Test(expected = NullPointerException.class) - public void collectIntoInitialNull() { - just1.collectInto(null, new BiConsumer() { - @Override - public void accept(Object a, Integer b) { } - }); - } - - @Test(expected = NullPointerException.class) - public void collectIntoCollectorNull() { - just1.collectInto(1, null); - } - - @Test(expected = NullPointerException.class) - public void composeNull() { - just1.compose(null); - } - - @Test(expected = NullPointerException.class) - public void concatMapNull() { - just1.concatMap(null); - } - @Test(expected = NullPointerException.class) public void concatMapReturnsNull() { just1.concatMap(new Function>() { @@ -897,11 +460,6 @@ public Observable apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void concatMapIterableNull() { - just1.concatMapIterable(null); - } - @Test(expected = NullPointerException.class) public void concatMapIterableReturnNull() { just1.concatMapIterable(new Function>() { @@ -927,21 +485,6 @@ public Iterator iterator() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void concatWithNull() { - just1.concatWith((ObservableSource)null); - } - - @Test(expected = NullPointerException.class) - public void containsNull() { - just1.contains(null); - } - - @Test(expected = NullPointerException.class) - public void debounceFunctionNull() { - just1.debounce(null); - } - @Test(expected = NullPointerException.class) public void debounceFunctionReturnsNull() { just1.debounce(new Function>() { @@ -952,26 +495,6 @@ public Observable apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void debounceTimedUnitNull() { - just1.debounce(1, null); - } - - @Test(expected = NullPointerException.class) - public void debounceTimedSchedulerNull() { - just1.debounce(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void defaultIfEmptyNull() { - just1.defaultIfEmpty(null); - } - - @Test(expected = NullPointerException.class) - public void delayWithFunctionNull() { - just1.delay(null); - } - @Test(expected = NullPointerException.class) public void delayWithFunctionReturnsNull() { just1.delay(new Function>() { @@ -982,61 +505,6 @@ public Observable apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void delayTimedUnitNull() { - just1.delay(1, null); - } - - @Test(expected = NullPointerException.class) - public void delayTimedSchedulerNull() { - just1.delay(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void delaySubscriptionTimedUnitNull() { - just1.delaySubscription(1, null); - } - - @Test(expected = NullPointerException.class) - public void delaySubscriptionTimedSchedulerNull() { - just1.delaySubscription(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void delaySubscriptionOtherNull() { - just1.delaySubscription((Observable)null); - } - - @Test(expected = NullPointerException.class) - public void delaySubscriptionFunctionNull() { - just1.delaySubscription((Observable)null); - } - - @Test(expected = NullPointerException.class) - public void delayBothInitialSupplierNull() { - just1.delay(null, new Function>() { - @Override - public Observable apply(Integer v) { - return just1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void delayBothInitialSupplierReturnsNull() { - just1.delay(null, new Function>() { - @Override - public Observable apply(Integer v) { - return just1; - } - }).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void delayBothItemSupplierNull() { - just1.delay(just1, null); - } - @Test(expected = NullPointerException.class) public void delayBothItemSupplierReturnsNull() { just1.delay(just1 @@ -1048,21 +516,6 @@ public Observable apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void distinctFunctionNull() { - just1.distinct(null); - } - - @Test(expected = NullPointerException.class) - public void distinctSupplierNull() { - just1.distinct(new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, null); - } - @Test(expected = NullPointerException.class) public void distinctSupplierReturnsNull() { just1.distinct(new Function() { @@ -1088,16 +541,6 @@ public Object apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void distinctUntilChangedFunctionNull() { - just1.distinctUntilChanged((Function)null); - } - - @Test(expected = NullPointerException.class) - public void distinctUntilChangedBiPredicateNull() { - just1.distinctUntilChanged((BiPredicate)null); - } - @Test public void distinctUntilChangedFunctionReturnsNull() { Observable.range(1, 2).distinctUntilChanged(new Function() { @@ -1108,84 +551,6 @@ public Object apply(Integer v) { }).test().assertResult(1); } - @Test(expected = NullPointerException.class) - public void doOnDisposeNull() { - just1.doOnDispose(null); - } - - @Test(expected = NullPointerException.class) - public void doOnCompleteNull() { - just1.doOnComplete(null); - } - - @Test(expected = NullPointerException.class) - public void doOnEachSupplierNull() { - just1.doOnEach((Consumer>)null); - } - - @Test(expected = NullPointerException.class) - public void doOnEachSubscriberNull() { - just1.doOnEach((Observer)null); - } - - @Test(expected = NullPointerException.class) - public void doOnErrorNull() { - just1.doOnError(null); - } - - @Test(expected = NullPointerException.class) - public void doOnLifecycleOnSubscribeNull() { - just1.doOnLifecycle(null, Functions.EMPTY_ACTION); - } - - @Test(expected = NullPointerException.class) - public void doOnLifecycleOnDisposeNull() { - just1.doOnLifecycle(new Consumer() { - @Override - public void accept(Disposable d) { } - }, null); - } - - @Test(expected = NullPointerException.class) - public void doOnNextNull() { - just1.doOnNext(null); - } - - @Test(expected = NullPointerException.class) - public void doOnSubscribeNull() { - just1.doOnSubscribe(null); - } - - @Test(expected = NullPointerException.class) - public void doOnTerminatedNull() { - just1.doOnTerminate(null); - } - - @Test(expected = NullPointerException.class) - public void elementAtNull() { - just1.elementAt(1, null); - } - - @Test(expected = NullPointerException.class) - public void filterNull() { - just1.filter(null); - } - - @Test(expected = NullPointerException.class) - public void doAfterTerminateNull() { - just1.doAfterTerminate(null); - } - - @Test(expected = NullPointerException.class) - public void firstNull() { - just1.first(null); - } - - @Test(expected = NullPointerException.class) - public void flatMapNull() { - just1.flatMap(null); - } - @Test(expected = NullPointerException.class) public void flatMapFunctionReturnsNull() { just1.flatMap(new Function>() { @@ -1196,21 +561,6 @@ public Observable apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void flatMapNotificationOnNextNull() { - just1.flatMap(null, new Function>() { - @Override - public Observable apply(Throwable e) { - return just1; - } - }, new Supplier>() { - @Override - public Observable get() { - return just1; - } - }); - } - @Test(expected = NullPointerException.class) public void flatMapNotificationOnNextReturnsNull() { just1.flatMap(new Function>() { @@ -1231,36 +581,6 @@ public Observable get() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void flatMapNotificationOnErrorNull() { - just1.flatMap(new Function>() { - @Override - public Observable apply(Integer v) { - return just1; - } - }, null, new Supplier>() { - @Override - public Observable get() { - return just1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void flatMapNotificationOnCompleteNull() { - just1.flatMap(new Function>() { - @Override - public Observable apply(Integer v) { - return just1; - } - }, new Function>() { - @Override - public Observable apply(Throwable e) { - return just1; - } - }, null); - } - @Test(expected = NullPointerException.class) public void flatMapNotificationOnCompleteReturnsNull() { just1.flatMap(new Function>() { @@ -1281,16 +601,6 @@ public Observable get() { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void flatMapCombinerMapperNull() { - just1.flatMap(null, new BiFunction() { - @Override - public Object apply(Integer a, Object b) { - return 1; - } - }); - } - @Test(expected = NullPointerException.class) public void flatMapCombinerMapperReturnsNull() { just1.flatMap(new Function>() { @@ -1306,16 +616,6 @@ public Object apply(Integer a, Object b) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void flatMapCombinerCombinerNull() { - just1.flatMap(new Function>() { - @Override - public Observable apply(Integer v) { - return just1; - } - }, null); - } - @Test(expected = NullPointerException.class) public void flatMapCombinerCombinerReturnsNull() { just1.flatMap(new Function>() { @@ -1331,11 +631,6 @@ public Object apply(Integer a, Integer b) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void flatMapIterableMapperNull() { - just1.flatMapIterable(null); - } - @Test(expected = NullPointerException.class) public void flatMapIterableMapperReturnsNull() { just1.flatMapIterable(new Function>() { @@ -1371,16 +666,6 @@ public Iterable apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void flatMapIterableCombinerNull() { - just1.flatMapIterable(new Function>() { - @Override - public Iterable apply(Integer v) { - return Arrays.asList(1); - } - }, null); - } - @Test(expected = NullPointerException.class) public void flatMapIterableCombinerReturnsNull() { just1.flatMapIterable(new Function>() { @@ -1396,44 +681,6 @@ public Object apply(Integer a, Integer b) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void forEachNull() { - just1.forEach(null); - } - - @Test(expected = NullPointerException.class) - public void forEachWhileNull() { - just1.forEachWhile(null); - } - - @Test(expected = NullPointerException.class) - public void forEachWhileOnErrorNull() { - just1.forEachWhile(new Predicate() { - @Override - public boolean test(Integer v) { - return true; - } - }, null); - } - - @Test(expected = NullPointerException.class) - public void forEachWhileOnCompleteNull() { - just1.forEachWhile(new Predicate() { - @Override - public boolean test(Integer v) { - return true; - } - }, new Consumer() { - @Override - public void accept(Throwable e) { } - }, null); - } - - @Test(expected = NullPointerException.class) - public void groupByNull() { - just1.groupBy(null); - } - public void groupByKeyNull() { just1.groupBy(new Function() { @Override @@ -1443,16 +690,6 @@ public Object apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void groupByValueNull() { - just1.groupBy(new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, null); - } - @Test(expected = NullPointerException.class) public void groupByValueReturnsNull() { just1.groupBy(new Function() { @@ -1468,16 +705,6 @@ public Object apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void lastNull() { - just1.last(null); - } - - @Test(expected = NullPointerException.class) - public void liftNull() { - just1.lift(null); - } - @Test(expected = NullPointerException.class) public void liftReturnsNull() { just1.lift(new ObservableOperator() { @@ -1488,11 +715,6 @@ public Observer apply(Observer observer) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void mapNull() { - just1.map(null); - } - @Test(expected = NullPointerException.class) public void mapReturnsNull() { just1.map(new Function() { @@ -1503,26 +725,6 @@ public Object apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void mergeWithNull() { - just1.mergeWith((ObservableSource)null); - } - - @Test(expected = NullPointerException.class) - public void observeOnNull() { - just1.observeOn(null); - } - - @Test(expected = NullPointerException.class) - public void ofTypeNull() { - just1.ofType(null); - } - - @Test(expected = NullPointerException.class) - public void onErrorResumeNextFunctionNull() { - just1.onErrorResumeNext(null); - } - @Test(expected = NullPointerException.class) public void onErrorResumeNextFunctionReturnsNull() { Observable.error(new TestException()).onErrorResumeNext(new Function>() { @@ -1533,21 +735,6 @@ public Observable apply(Throwable e) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void onErrorResumeNextObservableNull() { - just1.onErrorResumeWith(null); - } - - @Test(expected = NullPointerException.class) - public void onErrorReturnFunctionNull() { - just1.onErrorReturn(null); - } - - @Test(expected = NullPointerException.class) - public void onErrorReturnValueNull() { - just1.onErrorReturnItem(null); - } - @Test(expected = NullPointerException.class) public void onErrorReturnFunctionReturnsNull() { Observable.error(new TestException()).onErrorReturn(new Function() { @@ -1558,11 +745,6 @@ public Object apply(Throwable e) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void publishFunctionNull() { - just1.publish(null); - } - @Test(expected = NullPointerException.class) public void publishFunctionReturnsNull() { just1.publish(new Function, Observable>() { @@ -1573,11 +755,6 @@ public Observable apply(Observable v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void reduceFunctionNull() { - just1.reduce(null); - } - @Test(expected = NullPointerException.class) public void reduceFunctionReturnsNull() { Observable.just(1, 1).reduce(new BiFunction() { @@ -1588,21 +765,6 @@ public Integer apply(Integer a, Integer b) { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void reduceSeedNull() { - just1.reduce(null, new BiFunction() { - @Override - public Object apply(Object a, Integer b) { - return 1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void reduceSeedFunctionNull() { - just1.reduce(1, null); - } - @Test(expected = NullPointerException.class) public void reduceSeedFunctionReturnsNull() { just1.reduce(1, new BiFunction() { @@ -1613,16 +775,6 @@ public Integer apply(Integer a, Integer b) { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void reduceWithSeedNull() { - just1.reduceWith(null, new BiFunction() { - @Override - public Object apply(Object a, Integer b) { - return 1; - } - }); - } - @Test(expected = NullPointerException.class) public void reduceWithSeedReturnsNull() { just1.reduceWith(new Supplier() { @@ -1638,16 +790,6 @@ public Object apply(Object a, Integer b) { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void repeatUntilNull() { - just1.repeatUntil(null); - } - - @Test(expected = NullPointerException.class) - public void repeatWhenNull() { - just1.repeatWhen(null); - } - @Test(expected = NullPointerException.class) public void repeatWhenFunctionReturnsNull() { just1.repeatWhen(new Function, Observable>() { @@ -1658,11 +800,6 @@ public Observable apply(Observable v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void replaySelectorNull() { - just1.replay((Function, Observable>)null); - } - @Test(expected = NullPointerException.class) public void replaySelectorReturnsNull() { just1.replay(new Function, Observable>() { @@ -1673,11 +810,6 @@ public Observable apply(Observable o) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void replayBoundedSelectorNull() { - just1.replay((Function, Observable>)null, 1, 1, TimeUnit.SECONDS); - } - @Test(expected = NullPointerException.class) public void replayBoundedSelectorReturnsNull() { just1.replay(new Function, Observable>() { @@ -1688,31 +820,6 @@ public Observable apply(Observable v) { }, 1, 1, TimeUnit.SECONDS).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void replayBoundedUnitNull() { - just1.replay(new Function, Observable>() { - @Override - public Observable apply(Observable v) { - return v; - } - }, 1, 1, null).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void replayBoundedSchedulerNull() { - just1.replay(new Function, Observable>() { - @Override - public Observable apply(Observable v) { - return v; - } - }, 1, 1, TimeUnit.SECONDS, null).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void replayTimeBoundedSelectorNull() { - just1.replay(null, 1, TimeUnit.SECONDS, Schedulers.single()); - } - @Test(expected = NullPointerException.class) public void replayTimeBoundedSelectorReturnsNull() { just1.replay(new Function, Observable>() { @@ -1723,66 +830,6 @@ public Observable apply(Observable v) { }, 1, TimeUnit.SECONDS, Schedulers.single()).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void replaySelectorTimeBoundedUnitNull() { - just1.replay(new Function, Observable>() { - @Override - public Observable apply(Observable v) { - return v; - } - }, 1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void replaySelectorTimeBoundedSchedulerNull() { - just1.replay(new Function, Observable>() { - @Override - public Observable apply(Observable v) { - return v; - } - }, 1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void replayTimeSizeBoundedUnitNull() { - just1.replay(1, 1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void replayTimeSizeBoundedSchedulerNull() { - just1.replay(1, 1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void replayTimeBoundedUnitNull() { - just1.replay(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void replayTimeBoundedSchedulerNull() { - just1.replay(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void retryFunctionNull() { - just1.retry((BiPredicate)null); - } - - @Test(expected = NullPointerException.class) - public void retryCountFunctionNull() { - just1.retry(1, null); - } - - @Test(expected = NullPointerException.class) - public void retryPredicateNull() { - just1.retry((Predicate)null); - } - - @Test(expected = NullPointerException.class) - public void retryWhenFunctionNull() { - just1.retryWhen(null); - } - @Test(expected = NullPointerException.class) public void retryWhenFunctionReturnsNull() { Observable.error(new TestException()).retryWhen(new Function, Observable>() { @@ -1793,36 +840,6 @@ public Observable apply(Observable f) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void retryUntil() { - just1.retryUntil(null); - } - - @Test(expected = NullPointerException.class) - public void safeSubscribeNull() { - just1.safeSubscribe(null); - } - - @Test(expected = NullPointerException.class) - public void sampleUnitNull() { - just1.sample(1, null); - } - - @Test(expected = NullPointerException.class) - public void sampleSchedulerNull() { - just1.sample(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void sampleObservableNull() { - just1.sample(null); - } - - @Test(expected = NullPointerException.class) - public void scanFunctionNull() { - just1.scan(null); - } - @Test(expected = NullPointerException.class) public void scanFunctionReturnsNull() { Observable.just(1, 1).scan(new BiFunction() { @@ -1833,21 +850,6 @@ public Integer apply(Integer a, Integer b) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void scanSeedNull() { - just1.scan(null, new BiFunction() { - @Override - public Object apply(Object a, Integer b) { - return 1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void scanSeedFunctionNull() { - just1.scan(1, null); - } - @Test(expected = NullPointerException.class) public void scanSeedFunctionReturnsNull() { just1.scan(1, new BiFunction() { @@ -1858,16 +860,6 @@ public Integer apply(Integer a, Integer b) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void scanSeedSupplierNull() { - just1.scanWith(null, new BiFunction() { - @Override - public Object apply(Object a, Integer b) { - return 1; - } - }); - } - @Test(expected = NullPointerException.class) public void scanSeedSupplierReturnsNull() { just1.scanWith(new Supplier() { @@ -1883,16 +875,6 @@ public Object apply(Object a, Integer b) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void scanSeedSupplierFunctionNull() { - just1.scanWith(new Supplier() { - @Override - public Object get() { - return 1; - } - }, null); - } - @Test(expected = NullPointerException.class) public void scanSeedSupplierFunctionReturnsNull() { just1.scanWith(new Supplier() { @@ -1908,46 +890,6 @@ public Object apply(Object a, Integer b) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void singleNull() { - just1.single(null); - } - - @Test(expected = NullPointerException.class) - public void skipTimedUnitNull() { - just1.skip(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void skipTimedSchedulerNull() { - just1.skip(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void skipLastTimedUnitNull() { - just1.skipLast(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void skipLastTimedSchedulerNull() { - just1.skipLast(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void skipUntilNull() { - just1.skipUntil(null); - } - - @Test(expected = NullPointerException.class) - public void skipWhileNull() { - just1.skipWhile(null); - } - - @Test(expected = NullPointerException.class) - public void startWithIterableNull() { - just1.startWithIterable((Iterable)null); - } - @Test(expected = NullPointerException.class) public void startWithIterableIteratorNull() { just1.startWithIterable(new Iterable() { @@ -1963,70 +905,6 @@ public void startWithIterableOneNull() { just1.startWithIterable(Arrays.asList(1, null)).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void startWithSingleNull() { - just1.startWithItem((Integer)null); - } - - @Test(expected = NullPointerException.class) - public void startWithObservableNull() { - just1.startWith((Observable)null); - } - - @Test(expected = NullPointerException.class) - public void startWithArrayNull() { - just1.startWithArray((Integer[])null); - } - - @Test(expected = NullPointerException.class) - public void startWithArrayOneNull() { - just1.startWithArray(1, null).blockingSubscribe(); - } - - @Test(expected = NullPointerException.class) - public void subscribeOnNextNull() { - just1.subscribe((Consumer)null); - } - - @Test(expected = NullPointerException.class) - public void subscribeOnErrorNull() { - just1.subscribe(new Consumer() { - @Override - public void accept(Integer e) { } - }, null); - } - - @Test(expected = NullPointerException.class) - public void subscribeOnCompleteNull() { - just1.subscribe(new Consumer() { - @Override - public void accept(Integer e) { } - }, new Consumer() { - @Override - public void accept(Throwable e) { } - }, null); - } - - @Test(expected = NullPointerException.class) - public void subscribeNull() { - just1.subscribe((Observer)null); - } - - @Test(expected = NullPointerException.class) - public void subscribeOnNull() { - just1.subscribeOn(null); - } - - @Test(expected = NullPointerException.class) - public void switchIfEmptyNull() { - just1.switchIfEmpty(null); - } - - @Test(expected = NullPointerException.class) - public void switchMapNull() { - just1.switchMap(null); - } - @Test(expected = NullPointerException.class) public void switchMapFunctionReturnsNull() { just1.switchMap(new Function>() { @@ -2037,96 +915,6 @@ public Observable apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void takeTimedUnitNull() { - just1.take(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void takeTimedSchedulerNull() { - just1.take(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void takeLastTimedUnitNull() { - just1.takeLast(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void takeLastSizeTimedUnitNull() { - just1.takeLast(1, 1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void takeLastTimedSchedulerNull() { - just1.takeLast(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void takeLastSizeTimedSchedulerNull() { - just1.takeLast(1, 1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void takeUntilPredicateNull() { - just1.takeUntil((Predicate)null); - } - - @Test(expected = NullPointerException.class) - public void takeUntilObservableNull() { - just1.takeUntil((Observable)null); - } - - @Test(expected = NullPointerException.class) - public void takeWhileNull() { - just1.takeWhile(null); - } - - @Test(expected = NullPointerException.class) - public void throttleFirstUnitNull() { - just1.throttleFirst(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void throttleFirstSchedulerNull() { - just1.throttleFirst(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void throttleLastUnitNull() { - just1.throttleLast(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void throttleLastSchedulerNull() { - just1.throttleLast(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void throttleWithTimeoutUnitNull() { - just1.throttleWithTimeout(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void throttleWithTimeoutSchedulerNull() { - just1.throttleWithTimeout(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void timeIntervalUnitNull() { - just1.timeInterval(null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void timeIntervalSchedulerNull() { - just1.timeInterval(TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void timeoutSelectorNull() { - just1.timeout(null); - } - @Test(expected = NullPointerException.class) public void timeoutSelectorReturnsNull() { just1.timeout(new Function>() { @@ -2137,46 +925,6 @@ public Observable apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void timeoutSelectorOtherNull() { - just1.timeout(new Function>() { - @Override - public Observable apply(Integer v) { - return just1; - } - }, null); - } - - @Test(expected = NullPointerException.class) - public void timeoutUnitNull() { - just1.timeout(1, null, Schedulers.single(), just1); - } - - @Test(expected = NullPointerException.class) - public void timeouOtherNull() { - just1.timeout(1, TimeUnit.SECONDS, Schedulers.single(), null); - } - - @Test(expected = NullPointerException.class) - public void timeouSchedulerNull() { - just1.timeout(1, TimeUnit.SECONDS, null, just1); - } - - @Test(expected = NullPointerException.class) - public void timeoutFirstNull() { - just1.timeout((Observable)null, new Function>() { - @Override - public Observable apply(Integer v) { - return just1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void timeoutFirstItemNull() { - just1.timeout(just1, null); - } - @Test(expected = NullPointerException.class) public void timeoutFirstItemReturnsNull() { Observable.just(1, 1).timeout(Observable.never(), new Function>() { @@ -2187,26 +935,6 @@ public Observable apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void timestampUnitNull() { - just1.timestamp(null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void timestampSchedulerNull() { - just1.timestamp(TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void toNull() { - just1.to(null); - } - - @Test(expected = NullPointerException.class) - public void toListNull() { - just1.toList(null); - } - @Test(expected = NullPointerException.class) public void toListSupplierReturnsNull() { just1.toList(new Supplier>() { @@ -2217,26 +945,6 @@ public Collection get() { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void toSortedListNull() { - just1.toSortedList(null); - } - - @Test(expected = NullPointerException.class) - public void toMapKeyNull() { - just1.toMap(null); - } - - @Test(expected = NullPointerException.class) - public void toMapValueNull() { - just1.toMap(new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, null); - } - @Test public void toMapValueSelectorReturnsNull() { just1.toMap(new Function() { @@ -2252,21 +960,6 @@ public Object apply(Integer v) { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void toMapMapSupplierNull() { - just1.toMap(new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, null); - } - @Test(expected = NullPointerException.class) public void toMapMapSupplierReturnsNull() { just1.toMap(new Function() { @@ -2287,21 +980,6 @@ public Map get() { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void toMultimapKeyNull() { - just1.toMultimap(null); - } - - @Test(expected = NullPointerException.class) - public void toMultimapValueNull() { - just1.toMultimap(new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, null); - } - @Test public void toMultiMapValueSelectorReturnsNullAllowed() { just1.toMap(new Function() { @@ -2317,21 +995,6 @@ public Object apply(Integer v) { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void toMultimapMapMapSupplierNull() { - just1.toMultimap(new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, new Function() { - @Override - public Object apply(Integer v) { - return v; - } - }, null); - } - @Test(expected = NullPointerException.class) public void toMultimapMapSupplierReturnsNull() { just1.toMultimap(new Function() { @@ -2352,26 +1015,6 @@ public Map> get() { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void toMultimapMapMapCollectionSupplierNull() { - just1.toMultimap(new Function() { - @Override - public Integer apply(Integer v) { - return v; - } - }, new Function() { - @Override - public Integer apply(Integer v) { - return v; - } - }, new Supplier>>() { - @Override - public Map> get() { - return new HashMap<>(); - } - }, null); - } - @Test(expected = NullPointerException.class) public void toMultimapMapCollectionSupplierReturnsNull() { just1.toMultimap(new Function() { @@ -2397,56 +1040,6 @@ public Collection apply(Integer v) { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void unsafeSubscribeNull() { - just1.subscribe((Observer)null); - } - - @Test(expected = NullPointerException.class) - public void unsubscribeOnNull() { - just1.unsubscribeOn(null); - } - - @Test(expected = NullPointerException.class) - public void windowTimedUnitNull() { - just1.window(1, null, Schedulers.single()); - } - - @Test(expected = NullPointerException.class) - public void windowSizeTimedUnitNull() { - just1.window(1, null, Schedulers.single(), 1); - } - - @Test(expected = NullPointerException.class) - public void windowTimedSchedulerNull() { - just1.window(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void windowSizeTimedSchedulerNull() { - just1.window(1, TimeUnit.SECONDS, null, 1); - } - - @Test(expected = NullPointerException.class) - public void windowBoundaryNull() { - just1.window((Observable)null); - } - - @Test(expected = NullPointerException.class) - public void windowOpenCloseOpenNull() { - just1.window(null, new Function>() { - @Override - public Observable apply(Object v) { - return just1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void windowOpenCloseCloseNull() { - just1.window(just1, null); - } - @Test(expected = NullPointerException.class) public void windowOpenCloseCloseReturnsNull() { Observable.never().window(just1, new Function>() { @@ -2457,21 +1050,6 @@ public Observable apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void withLatestFromOtherNull() { - just1.withLatestFrom(null, new BiFunction() { - @Override - public Object apply(Integer a, Object b) { - return 1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void withLatestFromCombinerNull() { - just1.withLatestFrom(just1, null); - } - @Test(expected = NullPointerException.class) public void withLatestFromCombinerReturnsNull() { just1.withLatestFrom(just1, new BiFunction() { @@ -2482,21 +1060,6 @@ public Object apply(Integer a, Integer b) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void zipWithIterableNull() { - just1.zipWith((Iterable)null, new BiFunction() { - @Override - public Object apply(Integer a, Integer b) { - return 1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void zipWithIterableCombinerNull() { - just1.zipWith(Arrays.asList(1), null); - } - @Test(expected = NullPointerException.class) public void zipWithIterableCombinerReturnsNull() { just1.zipWith(Arrays.asList(1), new BiFunction() { @@ -2532,21 +1095,6 @@ public Object apply(Integer a, Integer b) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void zipWithObservableNull() { - just1.zipWith((Observable)null, new BiFunction() { - @Override - public Object apply(Integer a, Integer b) { - return 1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void zipWithCombinerNull() { - just1.zipWith(just1, null); - } - @Test(expected = NullPointerException.class) public void zipWithCombinerReturnsNull() { just1.zipWith(just1, new BiFunction() { diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableReduceTests.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableReduceTests.java index 8dec71b98e9..01c2106affe 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableReduceTests.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableReduceTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableScanTests.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableScanTests.java index bc73a886b24..8bc33ac19f8 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableScanTests.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableScanTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableStartWithTests.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableStartWithTests.java index 9c9261273c3..8e0fe35add0 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableStartWithTests.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableStartWithTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableSubscriberTest.java index 60e8470ca42..c8a1047fe39 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableTest.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableTest.java index c3110eac3fb..87e6463d3cd 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableTest.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -1039,13 +1039,6 @@ public void emptyIsEmpty() { // }}); // } - @Test(expected = NullPointerException.class) - public void forEachWithNull() { - Observable.error(new Exception("boo")) - // - .forEach(null); - } - @Test public void extend() { final TestObserver to = new TestObserver<>(); diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableThrottleLastTests.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableThrottleLastTests.java index e93f9409e0c..d8107cc4344 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableThrottleLastTests.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableThrottleLastTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -13,10 +13,10 @@ package io.reactivex.rxjava3.observable; -import static org.mockito.Mockito.inOrder; - import java.util.concurrent.TimeUnit; +import io.reactivex.rxjava3.exceptions.TestException; +import io.reactivex.rxjava3.functions.Action; import org.junit.Test; import org.mockito.InOrder; @@ -25,8 +25,78 @@ import io.reactivex.rxjava3.subjects.PublishSubject; import io.reactivex.rxjava3.testsupport.TestHelper; +import static org.mockito.Mockito.*; + public class ObservableThrottleLastTests extends RxJavaTest { + @Test + public void throttleLastWithDropCallbackException() throws Throwable { + Observer observer = TestHelper.mockObserver(); + + Action whenDisposed = mock(Action.class); + + TestScheduler s = new TestScheduler(); + PublishSubject o = PublishSubject.create(); + o.doOnDispose(whenDisposed) + .throttleLast(500, TimeUnit.MILLISECONDS, s, e -> { + if (e == 1) { + throw new TestException("Forced"); + } + }) + .subscribe(observer); + + // send events with simulated time increments + s.advanceTimeTo(0, TimeUnit.MILLISECONDS); + o.onNext(1); // skip + o.onNext(2); // try to deliver + s.advanceTimeTo(501, TimeUnit.MILLISECONDS); + + InOrder inOrder = inOrder(observer); + inOrder.verify(observer).onError(any(TestException.class)); + inOrder.verifyNoMoreInteractions(); + verify(whenDisposed).run(); + } + + @Test + public void throttleLastWithDropCallback() { + Observer observer = TestHelper.mockObserver(); + + Observer dropCallbackObserver = TestHelper.mockObserver(); + + TestScheduler s = new TestScheduler(); + PublishSubject o = PublishSubject.create(); + o.throttleLast(500, TimeUnit.MILLISECONDS, s, dropCallbackObserver::onNext).subscribe(observer); + + // send events with simulated time increments + s.advanceTimeTo(0, TimeUnit.MILLISECONDS); + o.onNext(1); // skip + o.onNext(2); // deliver + s.advanceTimeTo(501, TimeUnit.MILLISECONDS); + o.onNext(3); // skip + s.advanceTimeTo(600, TimeUnit.MILLISECONDS); + o.onNext(4); // skip + s.advanceTimeTo(700, TimeUnit.MILLISECONDS); + o.onNext(5); // skip + o.onNext(6); // deliver + s.advanceTimeTo(1001, TimeUnit.MILLISECONDS); + o.onNext(7); // deliver + s.advanceTimeTo(1501, TimeUnit.MILLISECONDS); + o.onComplete(); + + InOrder inOrder = inOrder(observer); + InOrder dropCallbackOrder = inOrder(dropCallbackObserver); + dropCallbackOrder.verify(dropCallbackObserver).onNext(1); + inOrder.verify(observer).onNext(2); + dropCallbackOrder.verify(dropCallbackObserver).onNext(3); + dropCallbackOrder.verify(dropCallbackObserver).onNext(4); + dropCallbackOrder.verify(dropCallbackObserver).onNext(5); + inOrder.verify(observer).onNext(6); + inOrder.verify(observer).onNext(7); + inOrder.verify(observer).onComplete(); + inOrder.verifyNoMoreInteractions(); + dropCallbackOrder.verifyNoMoreInteractions(); + } + @Test public void throttle() { Observer observer = TestHelper.mockObserver(); diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableThrottleWithTimeoutTests.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableThrottleWithTimeoutTests.java index bcacab55133..80f82fb5f4f 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableThrottleWithTimeoutTests.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableThrottleWithTimeoutTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableWindowTests.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableWindowTests.java index 9e1076017a4..4bc561bd1b2 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableWindowTests.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableWindowTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observable/ObservableZipTests.java b/src/test/java/io/reactivex/rxjava3/observable/ObservableZipTests.java index 1f671133485..b2b26719bb3 100644 --- a/src/test/java/io/reactivex/rxjava3/observable/ObservableZipTests.java +++ b/src/test/java/io/reactivex/rxjava3/observable/ObservableZipTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observers/DisposableCompletableObserverTest.java b/src/test/java/io/reactivex/rxjava3/observers/DisposableCompletableObserverTest.java index 19ee3e7f06d..fde1dc75de6 100644 --- a/src/test/java/io/reactivex/rxjava3/observers/DisposableCompletableObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/observers/DisposableCompletableObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observers/DisposableMaybeObserverTest.java b/src/test/java/io/reactivex/rxjava3/observers/DisposableMaybeObserverTest.java index 36dc6a6d3b3..7bd2f20a95a 100644 --- a/src/test/java/io/reactivex/rxjava3/observers/DisposableMaybeObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/observers/DisposableMaybeObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observers/DisposableObserverTest.java b/src/test/java/io/reactivex/rxjava3/observers/DisposableObserverTest.java index c2b766e7615..1b5b477552e 100644 --- a/src/test/java/io/reactivex/rxjava3/observers/DisposableObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/observers/DisposableObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observers/DisposableSingleObserverTest.java b/src/test/java/io/reactivex/rxjava3/observers/DisposableSingleObserverTest.java index b6239d65ee2..8dac144591f 100644 --- a/src/test/java/io/reactivex/rxjava3/observers/DisposableSingleObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/observers/DisposableSingleObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observers/ResourceCompletableObserverTest.java b/src/test/java/io/reactivex/rxjava3/observers/ResourceCompletableObserverTest.java index f0079405920..e2d1fa34bac 100644 --- a/src/test/java/io/reactivex/rxjava3/observers/ResourceCompletableObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/observers/ResourceCompletableObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observers/ResourceMaybeObserverTest.java b/src/test/java/io/reactivex/rxjava3/observers/ResourceMaybeObserverTest.java index 08d06044e76..257a5785f86 100644 --- a/src/test/java/io/reactivex/rxjava3/observers/ResourceMaybeObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/observers/ResourceMaybeObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observers/ResourceObserverTest.java b/src/test/java/io/reactivex/rxjava3/observers/ResourceObserverTest.java index 94934d82df3..543095582bb 100644 --- a/src/test/java/io/reactivex/rxjava3/observers/ResourceObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/observers/ResourceObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observers/ResourceSingleObserverTest.java b/src/test/java/io/reactivex/rxjava3/observers/ResourceSingleObserverTest.java index b720931088f..10f17e18d62 100644 --- a/src/test/java/io/reactivex/rxjava3/observers/ResourceSingleObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/observers/ResourceSingleObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/observers/SafeObserverTest.java b/src/test/java/io/reactivex/rxjava3/observers/SafeObserverTest.java index 3afced2d407..77b3d7b9b9f 100644 --- a/src/test/java/io/reactivex/rxjava3/observers/SafeObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/observers/SafeObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -221,6 +221,7 @@ public void dispose() { } @Test + @SuppressUndeliverable public void onNextAfterComplete() { TestObserver to = new TestObserver<>(); diff --git a/src/test/java/io/reactivex/rxjava3/observers/SerializedObserverTest.java b/src/test/java/io/reactivex/rxjava3/observers/SerializedObserverTest.java index e581012d9bc..689908f59fc 100644 --- a/src/test/java/io/reactivex/rxjava3/observers/SerializedObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/observers/SerializedObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,7 +24,7 @@ import org.junit.*; import io.reactivex.rxjava3.core.*; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.internal.util.ExceptionHelper; import io.reactivex.rxjava3.plugins.RxJavaPlugins; @@ -340,11 +340,11 @@ public void onNext(String t) { * * When using SynchronizedSubscriber we get this output: * - * p1: 18 p2: 68 => should be close to each other unless we have thread starvation + * {@code p1: 18 p2: 68 =>} should be close to each other unless we have thread starvation * * When using SerializedObserver we get: * - * p1: 1 p2: 2445261 => should be close to each other unless we have thread starvation + * {@code p1: 1 p2: 2445261 =>} should be close to each other unless we have thread starvation * * This demonstrates how SynchronizedSubscriber balances back and forth better, and blocks emission. * The real issue in this example is the async buffer-bloat, so we need backpressure. @@ -1142,4 +1142,29 @@ public void nullOnNext() { to.assertFailureAndMessage(NullPointerException.class, ExceptionHelper.nullWarning("onNext called with a null value.")); } + + @Test + @SuppressUndeliverable + public void onErrorQueuedUp() { + AtomicReference> soRef = new AtomicReference<>(); + TestObserverEx to = new TestObserverEx() { + @Override + public void onNext(Integer t) { + super.onNext(t); + soRef.get().onNext(2); + soRef.get().onError(new TestException()); + } + }; + + final SerializedObserver so = new SerializedObserver<>(to, true); + soRef.set(so); + + Disposable d = Disposable.empty(); + + so.onSubscribe(d); + + so.onNext(1); + + to.assertFailure(TestException.class, 1, 2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/observers/TestObserverTest.java b/src/test/java/io/reactivex/rxjava3/observers/TestObserverTest.java index 1e4a287cee0..f2d5f206c35 100644 --- a/src/test/java/io/reactivex/rxjava3/observers/TestObserverTest.java +++ b/src/test/java/io/reactivex/rxjava3/observers/TestObserverTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,15 +20,15 @@ import java.util.*; import java.util.concurrent.TimeUnit; -import org.junit.*; -import org.junit.rules.ExpectedException; +import org.junit.Test; +import org.junit.function.ThrowingRunnable; import org.mockito.InOrder; import org.reactivestreams.Subscriber; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Predicate; import io.reactivex.rxjava3.internal.functions.Functions; @@ -40,8 +40,15 @@ public class TestObserverTest extends RxJavaTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); + static void assertThrowsWithMessage(String message, Class clazz, ThrowingRunnable run) { + assertEquals(message, assertThrows(clazz, run).getMessage()); + } + + static void assertThrowsWithMessageMatchRegex(String regex, Class clazz, ThrowingRunnable run) { + assertTrue(assertThrows(clazz, run).getMessage().matches(regex)); + } + + private static final String ASSERT_MESSAGE_REGEX = "\nexpected: (.*)\n\\s*got: (.*)"; @Test public void assertTestObserver() { @@ -56,50 +63,44 @@ public void assertTestObserver() { @Test public void assertNotMatchCount() { - Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); - TestSubscriber subscriber = new TestSubscriber<>(); - oi.subscribe(subscriber); - - thrown.expect(AssertionError.class); - // FIXME different message format -// thrown.expectMessage("Number of items does not match. Provided: 1 Actual: 2"); - - subscriber.assertValue(1); - subscriber.assertValueCount(2); - subscriber.assertComplete().assertNoErrors(); + assertThrows(AssertionError.class, () -> { + Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); + TestSubscriber subscriber = new TestSubscriber<>(); + oi.subscribe(subscriber); + + subscriber.assertValue(1); + subscriber.assertValueCount(2); + subscriber.assertComplete().assertNoErrors(); + }); } @Test public void assertNotMatchValue() { - Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); - TestSubscriber subscriber = new TestSubscriber<>(); - oi.subscribe(subscriber); - - thrown.expect(AssertionError.class); - // FIXME different message format -// thrown.expectMessage("Value at index: 1 expected to be [3] (Integer) but was: [2] (Integer)"); - - subscriber.assertValues(1, 3); - subscriber.assertValueCount(2); - subscriber.assertComplete().assertNoErrors(); + assertThrows(AssertionError.class, () -> { + Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); + TestSubscriber subscriber = new TestSubscriber<>(); + oi.subscribe(subscriber); + + subscriber.assertValues(1, 3); + subscriber.assertValueCount(2); + subscriber.assertComplete().assertNoErrors(); + }); } @Test public void assertTerminalEventNotReceived() { - PublishProcessor p = PublishProcessor.create(); - TestSubscriber subscriber = new TestSubscriber<>(); - p.subscribe(subscriber); - - p.onNext(1); - p.onNext(2); + assertThrows(AssertionError.class, () -> { + PublishProcessor p = PublishProcessor.create(); + TestSubscriber subscriber = new TestSubscriber<>(); + p.subscribe(subscriber); - thrown.expect(AssertionError.class); - // FIXME different message format -// thrown.expectMessage("No terminal events received."); + p.onNext(1); + p.onNext(2); - subscriber.assertValues(1, 2); - subscriber.assertValueCount(2); - subscriber.assertComplete().assertNoErrors(); + subscriber.assertValues(1, 2); + subscriber.assertValueCount(2); + subscriber.assertComplete().assertNoErrors(); + }); } @Test @@ -853,16 +854,16 @@ public void errorMeansDisposed() { @Test public void assertValuePredicateEmpty() { - TestObserver to = new TestObserver<>(); + assertThrowsWithMessage("No values (latch = 0, values = 0, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); - Observable.empty().subscribe(to); + Observable.empty().subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("No values"); - to.assertValue(new Predicate() { - @Override public boolean test(final Object o) throws Exception { - return false; - } + to.assertValue(new Predicate() { + @Override public boolean test(final Object o) throws Exception { + return false; + } + }); }); } @@ -881,46 +882,46 @@ public void assertValuePredicateMatch() { @Test public void assertValuePredicateNoMatch() { - TestObserver to = new TestObserver<>(); + assertThrowsWithMessage("Value 1 (class: Integer) at position 0 did not pass the predicate (latch = 0, values = 1, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); - Observable.just(1).subscribe(to); + Observable.just(1).subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("Value not present"); - to.assertValue(new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o != 1; - } + to.assertValue(new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o != 1; + } + }); }); } @Test public void assertValuePredicateMatchButMore() { - TestObserver to = new TestObserver<>(); + assertThrowsWithMessage("The first value passed the predicate but this consumer received more than one value (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); - Observable.just(1, 2).subscribe(to); + Observable.just(1, 2).subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("Value present but other values as well"); - to.assertValue(new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o == 1; - } + to.assertValue(new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o == 1; + } + }); }); } @Test public void assertValueAtPredicateEmpty() { - TestObserver to = new TestObserver<>(); + assertThrowsWithMessage("No values (latch = 0, values = 0, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); - Observable.empty().subscribe(to); + Observable.empty().subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("No values"); - to.assertValueAt(0, new Predicate() { - @Override public boolean test(final Object o) throws Exception { - return false; - } + to.assertValueAt(0, new Predicate() { + @Override public boolean test(final Object o) throws Exception { + return false; + } + }); }); } @@ -939,43 +940,58 @@ public void assertValueAtPredicateMatch() { @Test public void assertValueAtPredicateNoMatch() { - TestObserver to = new TestObserver<>(); + assertThrowsWithMessage("Value 3 (class: Integer) at position 2 did not pass the predicate (latch = 0, values = 3, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); - Observable.just(1, 2, 3).subscribe(to); + Observable.just(1, 2, 3).subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("Value not present"); - to.assertValueAt(2, new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o != 3; - } + to.assertValueAt(2, new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o != 3; + } + }); }); } @Test public void assertValueAtInvalidIndex() { - TestObserver to = new TestObserver<>(); + assertThrowsWithMessage("Index 2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); - Observable.just(1, 2).subscribe(to); + Observable.just(1, 2).subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("Invalid index: 2 (latch = 0, values = 2, errors = 0, completions = 1)"); - to.assertValueAt(2, new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o == 1; - } + to.assertValueAt(2, new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o == 1; + } + }); + }); + } + + @Test + public void assertValueAtInvalidIndexNegative() { + assertThrowsWithMessage("Index -2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); + + Observable.just(1, 2).subscribe(to); + + to.assertValueAt(-2, new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o == 1; + } + }); }); } @Test public void assertValueAtIndexEmpty() { - TestObserver to = new TestObserver<>(); + assertThrowsWithMessage("No values (latch = 0, values = 0, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); - Observable.empty().subscribe(to); + Observable.empty().subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("No values"); - to.assertValueAt(0, "a"); + to.assertValueAt(0, "a"); + }); } @Test @@ -989,24 +1005,134 @@ public void assertValueAtIndexMatch() { @Test public void assertValueAtIndexNoMatch() { - TestObserver to = new TestObserver<>(); + assertThrowsWithMessage("\nexpected: b (class: String)\ngot: c (class: String); Value at position 2 differ (latch = 0, values = 3, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); + + Observable.just("a", "b", "c").subscribe(to); + + to.assertValueAt(2, "b"); + }); + } - Observable.just("a", "b", "c").subscribe(to); + @Test + public void assertValueAtIndexThrowsMessageMatchRegex() { + assertThrowsWithMessageMatchRegex(ASSERT_MESSAGE_REGEX, AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); + + Observable.just("a", "b", "c").subscribe(to); + + to.assertValueAt(2, "b"); + }); + } + + @Test + public void assertValuesCountNoMatch() { + assertThrowsWithMessage("\nexpected: 2 [a, b]\ngot: 3 [a, b, c]; Value count differs (latch = 0, values = 3, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); + + Observable.just("a", "b", "c").subscribe(to); + + to.assertValues("a", "b"); + }); + } + + @Test + public void assertValuesCountThrowsMessageMatchRegex() { + assertThrowsWithMessageMatchRegex(ASSERT_MESSAGE_REGEX, AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); + + Observable.just("a", "b", "c").subscribe(to); + + to.assertValues("a", "b"); + }); + } + + @Test + public void assertValuesNoMatch() { + assertThrowsWithMessage("\nexpected: d (class: String)\ngot: c (class: String); Value at position 2 differ (latch = 0, values = 3, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); + + Observable.just("a", "b", "c").subscribe(to); + + to.assertValues("a", "b", "d"); + }); + } + + @Test + public void assertValuesThrowsMessageMatchRegex() { + assertThrowsWithMessageMatchRegex(ASSERT_MESSAGE_REGEX, AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); + + Observable.just("a", "b", "c").subscribe(to); + + to.assertValues("a", "b", "d"); + }); + } + + @Test + public void assertValueCountNoMatch() { + assertThrowsWithMessage("\nexpected: 2\ngot: 3; Value counts differ (latch = 0, values = 3, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); + + Observable.just("a", "b", "c").subscribe(to); + + to.assertValueCount(2); + }); + } + + @Test + public void assertValueCountThrowsMessageMatchRegex() { + assertThrowsWithMessageMatchRegex(ASSERT_MESSAGE_REGEX, AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); + + Observable.just("a", "b", "c").subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("expected: b (class: String) but was: c (class: String) (latch = 0, values = 3, errors = 0, completions = 1)"); - to.assertValueAt(2, "b"); + to.assertValueCount(2); + }); + } + + @Test + public void assertValueSequenceNoMatch() { + assertThrowsWithMessage("\nexpected: d (class: String)\ngot: c (class: String); Value at position 2 differ (latch = 0, values = 3, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); + + Observable.just("a", "b", "c").subscribe(to); + + to.assertValueSequence(Arrays.asList("a", "b", "d")); + }); + } + + @Test + public void assertValueSequenceThrowsMessageMatchRegex() { + assertThrowsWithMessageMatchRegex(ASSERT_MESSAGE_REGEX, AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); + + Observable.just("a", "b", "c").subscribe(to); + + to.assertValueSequence(Arrays.asList("a", "b", "d")); + }); } @Test public void assertValueAtIndexInvalidIndex() { - TestObserver to = new TestObserver<>(); + assertThrowsWithMessage("Index 2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); - Observable.just("a", "b").subscribe(to); + Observable.just("a", "b").subscribe(to); + + to.assertValueAt(2, "c"); + }); + } + + @Test + public void assertValueAtIndexInvalidIndexNegative() { + assertThrowsWithMessage("Index -2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserver to = new TestObserver<>(); + + Observable.just("a", "b").subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("Invalid index: 2 (latch = 0, values = 2, errors = 0, completions = 1)"); - to.assertValueAt(2, "c"); + to.assertValueAt(-2, "c"); + }); } @Test @@ -1086,4 +1212,34 @@ public void assertValuesOnlyThrowsWhenErrored() { // expected } } + + @Test + public void onErrorIsNull() { + TestObserver to = TestObserver.create(); + to.onSubscribe(Disposable.empty()); + + to.onError(null); + + to.assertFailure(NullPointerException.class); + } + + @Test + public void awaitCountTimeout() { + TestObserver to = TestObserver.create(); + to.onSubscribe(Disposable.empty()); + to.awaitCount(1); + assertTrue(to.timeout); + } + + @Test(expected = RuntimeException.class) + public void awaitCountInterrupted() { + try { + TestObserver to = TestObserver.create(); + to.onSubscribe(Disposable.empty()); + Thread.currentThread().interrupt(); + to.awaitCount(1); + } finally { + Thread.interrupted(); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/internal/queue/SimpleQueueTest.java b/src/test/java/io/reactivex/rxjava3/operators/SimpleQueueTest.java similarity index 97% rename from src/test/java/io/reactivex/rxjava3/internal/queue/SimpleQueueTest.java rename to src/test/java/io/reactivex/rxjava3/operators/SimpleQueueTest.java index e5673b49bc7..b9f998c1deb 100644 --- a/src/test/java/io/reactivex/rxjava3/internal/queue/SimpleQueueTest.java +++ b/src/test/java/io/reactivex/rxjava3/operators/SimpleQueueTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,7 +16,7 @@ * https://github.com/JCTools/JCTools/blob/master/jctools-core/src/main/java/org/jctools/queues/atomic */ -package io.reactivex.rxjava3.internal.queue; +package io.reactivex.rxjava3.operators; import static org.junit.Assert.*; @@ -25,6 +25,7 @@ import org.junit.Test; import io.reactivex.rxjava3.core.RxJavaTest; +import io.reactivex.rxjava3.internal.queue.MpscLinkedQueue; public class SimpleQueueTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelCollectTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelCollectTest.java index 1a94b3c2471..f582966cf96 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelCollectTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelCollectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -163,4 +163,11 @@ public void accept(List a, Object b) throws Exception { RxJavaPlugins.reset(); } } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeParallel( + pf -> pf.collect(ArrayList::new, ArrayList::add) + ); + } } diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelDoOnNextTryTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelDoOnNextTryTest.java index 0ba01a05fd3..ba76f69cfb5 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelDoOnNextTryTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelDoOnNextTryTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -384,4 +384,23 @@ public void filterInvalidSourceConditional() { RxJavaPlugins.reset(); } } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> + ParallelFlowable.fromArray(f) + .doOnNext(v -> { }, ParallelFailureHandling.SKIP) + .sequential() + ); + } + + @Test + public void doubleOnSubscribeConditional() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> + ParallelFlowable.fromArray(f) + .doOnNext(v -> { }, ParallelFailureHandling.SKIP) + .filter(v -> true, ParallelFailureHandling.SKIP) + .sequential() + ); + } } diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelFilterTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelFilterTest.java index 1b774509866..31e9b9a7c41 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelFilterTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelFilterTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -119,4 +119,45 @@ public boolean test(Integer v) throws Exception { .test() .assertFailure(TestException.class); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> + ParallelFlowable.fromArray(f) + .filter(v -> true) + .sequential() + ); + } + + @Test + public void doubleOnSubscribeConditional() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> + ParallelFlowable.fromArray(f) + .filter(v -> true) + .filter(v -> true) + .sequential() + ); + } + + @Test + public void conditionalFalseTrue() { + Flowable.just(1) + .parallel() + .filter(v -> false) + .filter(v -> true) + .sequential() + .test() + .assertResult(); + } + + @Test + public void conditionalTrueFalse() { + Flowable.just(1) + .parallel() + .filter(v -> true) + .filter(v -> false) + .sequential() + .test() + .assertResult(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelFilterTryTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelFilterTryTest.java index 084566a0a5a..69400629897 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelFilterTryTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelFilterTryTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -373,4 +373,45 @@ public void filterInvalidSourceConditional() { RxJavaPlugins.reset(); } } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> + ParallelFlowable.fromArray(f) + .filter(v -> true, ParallelFailureHandling.SKIP) + .sequential() + ); + } + + @Test + public void doubleOnSubscribeConditional() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> + ParallelFlowable.fromArray(f) + .filter(v -> true, ParallelFailureHandling.SKIP) + .filter(v -> true, ParallelFailureHandling.SKIP) + .sequential() + ); + } + + @Test + public void conditionalFalseTrue() { + Flowable.just(1) + .parallel() + .filter(v -> false, ParallelFailureHandling.SKIP) + .filter(v -> true, ParallelFailureHandling.SKIP) + .sequential() + .test() + .assertResult(); + } + + @Test + public void conditionalTrueFalse() { + Flowable.just(1) + .parallel() + .filter(v -> true, ParallelFailureHandling.SKIP) + .filter(v -> false, ParallelFailureHandling.SKIP) + .sequential() + .test() + .assertResult(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelFlatMapIterableTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelFlatMapIterableTest.java index 916d3651b93..8c18de1b0b8 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelFlatMapIterableTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelFlatMapIterableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,7 +14,6 @@ package io.reactivex.rxjava3.parallel; import java.util.Arrays; -import java.util.stream.Stream; import org.junit.Test; @@ -25,7 +24,7 @@ public class ParallelFlatMapIterableTest extends RxJavaTest { @Test public void subscriberCount() { ParallelFlowableTest.checkSubscriberCount(Flowable.range(1, 5).parallel() - .flatMapStream(v -> Stream.of(1, 2, 3))); + .flatMapIterable(v -> Arrays.asList(1, 2, 3))); } @Test diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelFlowableTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelFlowableTest.java index 1d1f97163fe..c97bc5cf567 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelFlowableTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelFlowableTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelFromPublisherTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelFromPublisherTest.java index c790201d98b..7d4e684bb68 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelFromPublisherTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelFromPublisherTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,14 +21,16 @@ import org.junit.Test; import org.reactivestreams.*; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.subscribers.BasicFuseableSubscriber; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; -import io.reactivex.rxjava3.processors.UnicastProcessor; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.testsupport.*; @@ -48,7 +50,7 @@ protected void subscribeActual(Subscriber s) { .parallel(1, 1) .sequential(1) .test(0) - .assertFailure(MissingBackpressureException.class); + .assertFailure(QueueOverflowException.class); } @Test @@ -187,4 +189,107 @@ public Object apply(Integer v) throws Exception { assertTrue(map.toString(), e.contains("RxComputationThreadPool")); } } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(PublishProcessor.create().parallel()); + } + + @Test + public void syncFusedEmptyPoll() { + Flowable.just(1, 2) + .filter(v -> v == 1) + .compose(TestHelper.flowableStripBoundary()) + .parallel(1) + .sequential() + .test() + .assertResult(1); + } + + @Test + public void asyncFusedEmptyPoll() { + UnicastProcessor up = UnicastProcessor.create(); + up.onNext(1); + up.onNext(2); + up.onComplete(); + + up + .filter(v -> v == 1) + .compose(TestHelper.flowableStripBoundary()) + .parallel(1) + .sequential() + .test() + .assertResult(1); + } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.parallel().sequential()); + } + + @SuppressWarnings("unchecked") + @Test + public void requestUnboundedRace() { + FlowableSubscriber fs = new FlowableSubscriber() { + + @Override + public void onNext(@NonNull Integer t) { + } + + @Override + public void onError(Throwable t) { + } + + @Override + public void onComplete() { + } + + @Override + public void onSubscribe(@NonNull Subscription s) { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + TestHelper.race( + () -> s.request(Long.MAX_VALUE), + () -> s.request(Long.MAX_VALUE) + ); + } + } + }; + + PublishProcessor.create() + .parallel(1) + .subscribe(new FlowableSubscriber[] { fs }); + } + + @SuppressWarnings("unchecked") + @Test + public void requestRace() { + FlowableSubscriber fs = new FlowableSubscriber() { + + @Override + public void onNext(@NonNull Integer t) { + } + + @Override + public void onError(Throwable t) { + } + + @Override + public void onComplete() { + } + + @Override + public void onSubscribe(@NonNull Subscription s) { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + TestHelper.race( + () -> s.request(1), + () -> s.request(1) + ); + } + } + }; + + PublishProcessor.create() + .parallel(1) + .subscribe(new FlowableSubscriber[] { fs }); + } } diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelInvalid.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelInvalid.java index 39e8ac21cfd..6b54ca6847e 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelInvalid.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelInvalid.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelJoinTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelJoinTest.java index fb50a775f80..8ee41cb9739 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelJoinTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelJoinTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -14,14 +14,17 @@ package io.reactivex.rxjava3.parallel; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; import org.reactivestreams.Subscriber; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.processors.PublishProcessor; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; @@ -45,7 +48,7 @@ public int parallelism() { } .sequential(1) .test(0) - .assertFailure(MissingBackpressureException.class); + .assertFailure(QueueOverflowException.class); } @Test @@ -78,7 +81,7 @@ public int parallelism() { .sequential(1) .subscribe(ts); - ts.assertFailure(MissingBackpressureException.class, 1); + ts.assertFailure(QueueOverflowException.class, 1); } @Test @@ -108,7 +111,7 @@ public int parallelism() { .sequentialDelayError(1) .test(0) .requestMore(1) - .assertFailure(MissingBackpressureException.class, 1); + .assertFailure(QueueOverflowException.class, 1); } @Test @@ -145,7 +148,7 @@ public int parallelism() { ts.request(1); - ts.assertFailure(MissingBackpressureException.class, 1, 2); + ts.assertFailure(QueueOverflowException.class, 1, 2); } @Test @@ -326,4 +329,198 @@ public Integer apply(Integer v) throws Exception { .test() .assertFailure(TestException.class, 2, 3, 4); } + + @Test + public void takeUntil() { + Flowable.range(1, 10) + .parallel(1) + .sequential() + .takeUntil(v -> true) + .test(0L) + .requestMore(100) + .assertResult(1); + } + + @Test + public void takeUntilDelayError() { + Flowable.range(1, 10) + .parallel(1) + .sequentialDelayError() + .takeUntil(v -> true) + .test(0L) + .requestMore(100) + .assertResult(1); + } + + @Test + public void oneItemNext() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = pp.parallel(1) + .sequential() + .test(0L); + + pp.onNext(1); + + ts.requestMore(10) + .assertValuesOnly(1); + } + + @Test + public void delayErrorOneItemNext() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = pp.parallel(1) + .sequentialDelayError() + .test(0L); + + pp.onNext(1); + + ts.requestMore(10) + .assertValuesOnly(1); + } + + @Test + public void onNextWhileProcessingSlowPath() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = new TestSubscriber() { + @Override + public void onNext(@NonNull Integer t) { + super.onNext(t); + if (t == 1) { + pp.onNext(2); + } + } + }; + + ParallelFlowable.fromArray(pp) + .sequential() + .subscribeWith(ts); + + pp.onNext(1); + + ts + .assertValuesOnly(1, 2); + } + + @Test + public void delayErrorOnNextWhileProcessingSlowPath() { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = new TestSubscriber() { + @Override + public void onNext(@NonNull Integer t) { + super.onNext(t); + if (t == 1) { + pp.onNext(2); + } + } + }; + + ParallelFlowable.fromArray(pp) + .sequentialDelayError() + .subscribeWith(ts); + + pp.onNext(1); + + ts + .assertValuesOnly(1, 2); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported( + ParallelFlowable.fromArray(PublishProcessor.create()) + .sequential() + ); + } + + @Test + public void onNextMissingBackpressureRace() throws Throwable { + TestHelper.withErrorTracking(errors -> { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + + AtomicReference> ref1 = new AtomicReference<>(); + AtomicReference> ref2 = new AtomicReference<>(); + + Flowable f1 = new Flowable() { + @Override + public void subscribeActual(Subscriber s) { + s.onSubscribe(new BooleanSubscription()); + ref1.set(s); + } + }; + Flowable f2 = new Flowable() { + @Override + public void subscribeActual(Subscriber s) { + s.onSubscribe(new BooleanSubscription()); + ref2.set(s); + } + }; + + ParallelFlowable.fromArray(f1, f2) + .sequential(1) + .test(0) + ; + + TestHelper.race( + () -> { + ref1.get().onNext(1); + ref1.get().onNext(2); + }, + () -> { + ref2.get().onNext(3); + ref2.get().onNext(4); + } + ); + + errors.clear(); + } + }); + } + + @Test + public void onNextMissingBackpressureDelayErrorRace() throws Throwable { + TestHelper.withErrorTracking(errors -> { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + + AtomicReference> ref1 = new AtomicReference<>(); + AtomicReference> ref2 = new AtomicReference<>(); + + Flowable f1 = new Flowable() { + @Override + public void subscribeActual(Subscriber s) { + s.onSubscribe(new BooleanSubscription()); + ref1.set(s); + } + }; + Flowable f2 = new Flowable() { + @Override + public void subscribeActual(Subscriber s) { + s.onSubscribe(new BooleanSubscription()); + ref2.set(s); + } + }; + + ParallelFlowable.fromArray(f1, f2) + .sequentialDelayError(1) + .test(0) + ; + + TestHelper.race( + () -> { + ref1.get().onNext(1); + ref1.get().onNext(2); + }, + () -> { + ref2.get().onNext(3); + ref2.get().onNext(4); + } + ); + + errors.clear(); + } + }); + } } diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelMapTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelMapTest.java index e45034d416c..493b74d34ed 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelMapTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelMapTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -15,15 +15,19 @@ import static org.junit.Assert.*; -import java.util.*; +import java.util.List; import java.util.concurrent.TimeUnit; import org.junit.Test; +import org.reactivestreams.Subscriber; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.testsupport.TestHelper; @@ -199,4 +203,25 @@ public void doubleOnSubscribe() { .filter(v -> true) ); } + + @Test + public void conditionalCancelIgnored() { + Flowable f = new Flowable() { + @Override + protected void subscribeActual(@NonNull Subscriber<@NonNull ? super @NonNull Integer> s) { + @SuppressWarnings("unchecked") + ConditionalSubscriber subscriber = (ConditionalSubscriber)s; + subscriber.onSubscribe(new BooleanSubscription()); + subscriber.tryOnNext(1); + subscriber.tryOnNext(2); + } + }; + + ParallelFlowable.fromArray(f) + .map(v -> { throw new TestException(); }) + .filter(v -> true) + .sequential() + .test() + .assertFailure(TestException.class); + } } diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelMapTryTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelMapTryTest.java index d56669d755c..a6d0de2d92e 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelMapTryTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelMapTryTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelPeekTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelPeekTest.java index 85b311847ae..93d72ef9f60 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelPeekTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelPeekTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,7 @@ import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.plugins.RxJavaPlugins; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class ParallelPeekTest extends RxJavaTest { @@ -37,6 +37,7 @@ public void subscriberCount() { } @Test + @SuppressUndeliverable public void onSubscribeCrash() { Flowable.range(1, 5) .parallel() @@ -125,6 +126,7 @@ public void run() throws Exception { } @Test + @SuppressUndeliverable public void onCompleteCrash() { Flowable.just(1) .parallel() @@ -194,4 +196,13 @@ public void run() throws Exception { RxJavaPlugins.reset(); } } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeFlowable(f -> + ParallelFlowable.fromArray(f) + .doOnComplete(() -> { }) + .sequential() + ); + } } diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelReduceFullTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelReduceFullTest.java index 25d72af909a..d9a43a247c5 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelReduceFullTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelReduceFullTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,7 +16,7 @@ import static org.junit.Assert.*; import java.io.IOException; -import java.util.List; +import java.util.*; import org.junit.Test; @@ -164,4 +164,11 @@ public Integer apply(Integer a, Integer b) throws Exception { .test() .assertFailure(TestException.class); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeParallelToFlowable( + pf -> pf.reduce((a, b) -> a) + ); + } } diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelReduceTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelReduceTest.java index 5646b176b10..9c32f6afc8a 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelReduceTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelReduceTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -169,4 +169,11 @@ public List apply(List a, Object b) throws Exception { RxJavaPlugins.reset(); } } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeParallel( + pf -> pf.reduce(ArrayList::new, (a, b) -> a) + ); + } } diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelRunOnTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelRunOnTest.java index 907b0bb8894..44a860263a7 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelRunOnTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelRunOnTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -98,7 +98,7 @@ public void subscribe(Subscriber[] subscribers) { .runOn(ImmediateThinScheduler.INSTANCE, 1) .sequential(1) .test(0) - .assertFailure(MissingBackpressureException.class); + .assertFailure(QueueOverflowException.class); } @Test @@ -322,4 +322,60 @@ public void onNext(Integer t) { ts.assertResult(1); } + + @Test + public void doubleOnSubscribe() { + TestHelper.checkDoubleOnSubscribeParallel(pf -> pf.runOn(ImmediateThinScheduler.INSTANCE)); + } + + @Test + public void doubleOnSubscribeConditional() { + TestHelper.checkDoubleOnSubscribeParallel(pf -> + pf.runOn(ImmediateThinScheduler.INSTANCE) + .filter(v -> true) + ); + } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported( + ParallelFlowable.fromArray(PublishProcessor.create()) + .runOn(ImmediateThinScheduler.INSTANCE) + ); + } + + @SuppressWarnings("unchecked") + @Test + public void asManyItemsAsRequested() { + TestSubscriber ts = new TestSubscriber<>(0); + + Flowable.range(1, 5) + .parallel(1) + .runOn(ImmediateThinScheduler.INSTANCE) + .subscribe(new Subscriber[] { + ts + }); + + ts + .requestMore(5) + .assertResult(1, 2, 3, 4, 5); + } + + @SuppressWarnings("unchecked") + @Test + public void asManyItemsAsRequestedConditional() { + TestSubscriber ts = new TestSubscriber<>(0); + + Flowable.range(1, 5) + .parallel(1) + .runOn(ImmediateThinScheduler.INSTANCE) + .filter(v -> true) + .subscribe(new Subscriber[] { + ts + }); + + ts + .requestMore(5) + .assertResult(1, 2, 3, 4, 5); + } } diff --git a/src/test/java/io/reactivex/rxjava3/parallel/ParallelSortedJoinTest.java b/src/test/java/io/reactivex/rxjava3/parallel/ParallelSortedJoinTest.java index e7b5cda9b0d..9ba23c30c27 100644 --- a/src/test/java/io/reactivex/rxjava3/parallel/ParallelSortedJoinTest.java +++ b/src/test/java/io/reactivex/rxjava3/parallel/ParallelSortedJoinTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,6 +24,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.internal.functions.Functions; +import io.reactivex.rxjava3.internal.operators.parallel.ParallelSortedJoin; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.Schedulers; @@ -207,4 +208,32 @@ public void run() { TestHelper.race(r1, r2); } } + + @Test + public void badRequest() { + TestHelper.assertBadRequestReported(PublishProcessor.create().parallel().sorted(Functions.naturalComparator())); + } + + @Test + public void comparatorCrashWhileMainOnError() throws Throwable { + TestHelper.withErrorTracking(errors -> { + PublishProcessor> pp1 = PublishProcessor.create(); + PublishProcessor> pp2 = PublishProcessor.create(); + + new ParallelSortedJoin<>(ParallelFlowable.fromArray(pp1, pp2) + , (a, b) -> { + pp1.onError(new IOException()); + throw new TestException(); + }) + .test(); + + pp1.onNext(Arrays.asList(1)); + pp2.onNext(Arrays.asList(2)); + + pp1.onComplete(); + pp2.onComplete(); + + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); + } } diff --git a/src/test/java/io/reactivex/rxjava3/plugins/RxJavaPluginsTest.java b/src/test/java/io/reactivex/rxjava3/plugins/RxJavaPluginsTest.java index defc141800c..6aa166d118f 100644 --- a/src/test/java/io/reactivex/rxjava3/plugins/RxJavaPluginsTest.java +++ b/src/test/java/io/reactivex/rxjava3/plugins/RxJavaPluginsTest.java @@ -1,17 +1,14 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava3.plugins; @@ -592,6 +589,61 @@ public void onComplete() { .assertComplete(); } + @SuppressWarnings("rawtypes") + @Test + public void parallelFlowableStart() { + try { + RxJavaPlugins.setOnParallelSubscribe(new BiFunction() { + @Override + public Subscriber[] apply(ParallelFlowable f, final Subscriber[] t) { + return new Subscriber[] { new Subscriber() { + + @Override + public void onSubscribe(Subscription s) { + t[0].onSubscribe(s); + } + + @SuppressWarnings("unchecked") + @Override + public void onNext(Object value) { + t[0].onNext((Integer)value - 9); + } + + @Override + public void onError(Throwable e) { + t[0].onError(e); + } + + @Override + public void onComplete() { + t[0].onComplete(); + } + + } + }; + } + }); + + Flowable.range(10, 3) + .parallel(1) + .sequential() + .test() + .assertValues(1, 2, 3) + .assertNoErrors() + .assertComplete(); + } finally { + RxJavaPlugins.reset(); + } + // make sure the reset worked + Flowable.range(10, 3) + .parallel(1) + .sequential() + .test() + .assertValues(10, 11, 12) + .assertNoErrors() + .assertComplete(); + } + @SuppressWarnings("rawtypes") @Test public void singleCreate() { @@ -1176,6 +1228,7 @@ public void onComplete() { } AllSubscriber all = new AllSubscriber(); + Subscriber[] allArray = { all }; assertNull(RxJavaPlugins.onSubscribe(Observable.never(), null)); @@ -1197,6 +1250,10 @@ public void onComplete() { assertSame(all, RxJavaPlugins.onSubscribe(Maybe.never(), all)); + assertNull(RxJavaPlugins.onSubscribe(Flowable.never().parallel(), null)); + + assertSame(allArray, RxJavaPlugins.onSubscribe(Flowable.never().parallel(), allArray)); + final Scheduler s = ImmediateThinScheduler.INSTANCE; Supplier c = new Supplier() { @Override diff --git a/src/test/java/io/reactivex/rxjava3/processors/AsyncProcessorTest.java b/src/test/java/io/reactivex/rxjava3/processors/AsyncProcessorTest.java index 6daaf15245c..81afc972dc7 100644 --- a/src/test/java/io/reactivex/rxjava3/processors/AsyncProcessorTest.java +++ b/src/test/java/io/reactivex/rxjava3/processors/AsyncProcessorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,8 +26,8 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Consumer; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.subscribers.TestSubscriber; import io.reactivex.rxjava3.testsupport.*; @@ -112,6 +112,7 @@ public void subscribeAfterError() { } @Test + @SuppressUndeliverable public void error() { AsyncProcessor processor = AsyncProcessor.create(); @@ -424,6 +425,7 @@ public void run() { } @Test + @SuppressUndeliverable public void onErrorCancelRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { @@ -481,6 +483,7 @@ public void onNext(Object t) { } @Test + @SuppressUndeliverable public void onErrorCrossCancel() { AsyncProcessor p = AsyncProcessor.create(); @@ -523,4 +526,9 @@ public void onComplete() { ts1.assertResult(); ts2.assertEmpty(); } + + @Test + public void cancel() { + TestHelper.checkDisposed(AsyncProcessor.create()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/processors/BehaviorProcessorTest.java b/src/test/java/io/reactivex/rxjava3/processors/BehaviorProcessorTest.java index d49ba5f5658..991a599b82e 100644 --- a/src/test/java/io/reactivex/rxjava3/processors/BehaviorProcessorTest.java +++ b/src/test/java/io/reactivex/rxjava3/processors/BehaviorProcessorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -612,6 +612,36 @@ public void run() { } } + @Test + public void multipleSubscribersRemoveSomeRace() { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + final BehaviorProcessor p = BehaviorProcessor.create(); + + final TestSubscriber ts1 = p.test(); + final TestSubscriber ts2 = p.test(); + final TestSubscriber ts3 = p.test(); + + Runnable r1 = new Runnable() { + @Override + public void run() { + ts1.cancel(); + } + }; + + Runnable r2 = new Runnable() { + @Override + public void run() { + ts2.cancel(); + } + }; + + TestHelper.race(r1, r2); + + p.onNext(1); + ts3.assertValuesOnly(1); + } + } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void subscribeOnNextRace() { diff --git a/src/test/java/io/reactivex/rxjava3/processors/FlowableProcessorTest.java b/src/test/java/io/reactivex/rxjava3/processors/FlowableProcessorTest.java index ae659623e05..1575a5669c3 100644 --- a/src/test/java/io/reactivex/rxjava3/processors/FlowableProcessorTest.java +++ b/src/test/java/io/reactivex/rxjava3/processors/FlowableProcessorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/processors/MulticastProcessorTest.java b/src/test/java/io/reactivex/rxjava3/processors/MulticastProcessorTest.java index afa14b8deb8..0ac22cf1b2e 100644 --- a/src/test/java/io/reactivex/rxjava3/processors/MulticastProcessorTest.java +++ b/src/test/java/io/reactivex/rxjava3/processors/MulticastProcessorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/processors/PublishProcessorTest.java b/src/test/java/io/reactivex/rxjava3/processors/PublishProcessorTest.java index 7c413d9dc0f..380f6445189 100644 --- a/src/test/java/io/reactivex/rxjava3/processors/PublishProcessorTest.java +++ b/src/test/java/io/reactivex/rxjava3/processors/PublishProcessorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,7 +30,7 @@ import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subscribers.*; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class PublishProcessorTest extends FlowableProcessorTest { @@ -40,6 +40,7 @@ protected FlowableProcessor create() { } @Test + @SuppressUndeliverable public void completed() { PublishProcessor processor = PublishProcessor.create(); @@ -113,6 +114,7 @@ private void assertCompletedSubscriber(Subscriber subscriber) { } @Test + @SuppressUndeliverable public void error() { PublishProcessor processor = PublishProcessor.create(); @@ -434,6 +436,7 @@ public void onNext(Integer t) { } @Test + @SuppressUndeliverable public void crossCancelOnError() { final TestSubscriber ts1 = new TestSubscriber<>(); TestSubscriber ts2 = new TestSubscriber() { diff --git a/src/test/java/io/reactivex/rxjava3/processors/ReplayProcessorBoundedConcurrencyTest.java b/src/test/java/io/reactivex/rxjava3/processors/ReplayProcessorBoundedConcurrencyTest.java index 4590a6dec97..f080ce5e1d5 100644 --- a/src/test/java/io/reactivex/rxjava3/processors/ReplayProcessorBoundedConcurrencyTest.java +++ b/src/test/java/io/reactivex/rxjava3/processors/ReplayProcessorBoundedConcurrencyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/processors/ReplayProcessorConcurrencyTest.java b/src/test/java/io/reactivex/rxjava3/processors/ReplayProcessorConcurrencyTest.java index 3cacc0d67a2..3afe66dd252 100644 --- a/src/test/java/io/reactivex/rxjava3/processors/ReplayProcessorConcurrencyTest.java +++ b/src/test/java/io/reactivex/rxjava3/processors/ReplayProcessorConcurrencyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/processors/ReplayProcessorTest.java b/src/test/java/io/reactivex/rxjava3/processors/ReplayProcessorTest.java index bb4b97e68b8..35a877911bb 100644 --- a/src/test/java/io/reactivex/rxjava3/processors/ReplayProcessorTest.java +++ b/src/test/java/io/reactivex/rxjava3/processors/ReplayProcessorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,6 +26,7 @@ import org.mockito.*; import org.reactivestreams.*; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; @@ -46,6 +47,7 @@ protected FlowableProcessor create() { } @Test + @SuppressUndeliverable public void completed() { ReplayProcessor processor = ReplayProcessor.create(); @@ -70,6 +72,7 @@ public void completed() { } @Test + @SuppressUndeliverable public void completedStopsEmittingData() { ReplayProcessor channel = ReplayProcessor.create(); Subscriber observerA = TestHelper.mockSubscriber(); @@ -139,6 +142,7 @@ public void completedStopsEmittingData() { } @Test + @SuppressUndeliverable public void completedAfterError() { ReplayProcessor processor = ReplayProcessor.create(); @@ -169,6 +173,7 @@ private void assertCompletedSubscriber(Subscriber subscriber) { } @Test + @SuppressUndeliverable public void error() { ReplayProcessor processor = ReplayProcessor.create(); @@ -1199,6 +1204,30 @@ public void takeSizeAndTime() { .assertResult(2); } + @Test + public void takeSizeAndTime2() { + TestScheduler scheduler = new TestScheduler(); + + ReplayProcessor rp = ReplayProcessor.createWithTimeAndSize(1, TimeUnit.SECONDS, scheduler, 2); + + rp.onNext(1); + rp.onNext(2); + rp.onNext(3); + + TestSubscriber ts = new TestSubscriber() { + @Override + public void onNext(@NonNull Integer t) { + super.onNext(t); + cancel(); + onComplete(); + } + }; + + rp + .subscribeWith(ts) + .assertResult(2); + } + @Test public void takeSize() { ReplayProcessor rp = ReplayProcessor.createWithSize(2); @@ -1213,6 +1242,28 @@ public void takeSize() { .assertResult(2); } + @Test + public void takeSize2() { + ReplayProcessor rp = ReplayProcessor.createWithSize(2); + + rp.onNext(1); + rp.onNext(2); + rp.onNext(3); + + TestSubscriber ts = new TestSubscriber() { + @Override + public void onNext(@NonNull Integer t) { + super.onNext(t); + cancel(); + onComplete(); + } + }; + + rp + .subscribeWith(ts) + .assertResult(2); + } + @Test public void reentrantDrain() { TestScheduler scheduler = new TestScheduler(); @@ -1781,4 +1832,69 @@ public void timeAndSizeRemoveCorrectNumberOfOld() { rp.test().assertValuesOnly(4, 5); } -} + + @Test + public void terminationSubscriptionRaceUnbounded() throws Throwable { + for (int i = 1; i <= 10000; i++) { + ReplayProcessor source = ReplayProcessor.create(); + PublishProcessor sink = PublishProcessor.create(); + TestSubscriber subscriber = sink.test(); + Schedulers.computation().scheduleDirect(() -> { + // issue signals to the source in adherence to the reactive streams specification + source.onSubscribe(new BooleanSubscription()); + source.onNext("hello"); + source.onNext("world"); + source.onComplete(); + }); + Schedulers.computation().scheduleDirect(() -> { + // connect the source to the sink in parallel with the signals issued to the source + // note the cast() operator, which is here to detect non-String escapees + source.cast(String.class).subscribe(sink); + }); + subscriber.await().assertValues("hello", "world").assertComplete(); + } + } + + @Test + public void terminationSubscriptionRaceSizeBound() throws Throwable { + for (int i = 1; i <= 10000; i++) { + ReplayProcessor source = ReplayProcessor.createWithSize(20); + PublishProcessor sink = PublishProcessor.create(); + TestSubscriber subscriber = sink.test(); + Schedulers.computation().scheduleDirect(() -> { + // issue signals to the source in adherence to the reactive streams specification + source.onSubscribe(new BooleanSubscription()); + source.onNext("hello"); + source.onNext("world"); + source.onComplete(); + }); + Schedulers.computation().scheduleDirect(() -> { + // connect the source to the sink in parallel with the signals issued to the source + // note the cast() operator, which is here to detect non-String escapees + source.cast(String.class).subscribe(sink); + }); + subscriber.await().assertValues("hello", "world").assertComplete(); + } + } + + @Test + public void terminationSubscriptionRaceTimeBound() throws Throwable { + for (int i = 1; i <= 10000; i++) { + ReplayProcessor source = ReplayProcessor.createWithTime(20, TimeUnit.MINUTES, Schedulers.computation()); + PublishProcessor sink = PublishProcessor.create(); + TestSubscriber subscriber = sink.test(); + Schedulers.computation().scheduleDirect(() -> { + // issue signals to the source in adherence to the reactive streams specification + source.onSubscribe(new BooleanSubscription()); + source.onNext("hello"); + source.onNext("world"); + source.onComplete(); + }); + Schedulers.computation().scheduleDirect(() -> { + // connect the source to the sink in parallel with the signals issued to the source + // note the cast() operator, which is here to detect non-String escapees + source.cast(String.class).subscribe(sink); + }); + subscriber.await().assertValues("hello", "world").assertComplete(); + } + }} diff --git a/src/test/java/io/reactivex/rxjava3/processors/SerializedProcessorTest.java b/src/test/java/io/reactivex/rxjava3/processors/SerializedProcessorTest.java index fc50ade3ef8..515b8d1430b 100644 --- a/src/test/java/io/reactivex/rxjava3/processors/SerializedProcessorTest.java +++ b/src/test/java/io/reactivex/rxjava3/processors/SerializedProcessorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,6 +20,7 @@ import org.junit.Test; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; @@ -664,4 +665,27 @@ public void run() { ts.assertEmpty(); } } + + @Test + public void onErrorQueued() { + FlowableProcessor sp = PublishProcessor.create().toSerialized(); + + TestSubscriber ts = new TestSubscriber() { + @Override + public void onNext(@NonNull Integer t) { + super.onNext(t); + if (t == 1) { + sp.onNext(2); + sp.onSubscribe(new BooleanSubscription()); + sp.onError(new TestException()); + } + } + }; + + sp.subscribe(ts); + + sp.onNext(1); + + ts.assertFailure(TestException.class, 1); // errors skip ahead + } } diff --git a/src/test/java/io/reactivex/rxjava3/processors/UnicastProcessorTest.java b/src/test/java/io/reactivex/rxjava3/processors/UnicastProcessorTest.java index 002d6a17d3f..f65cc46a5ed 100644 --- a/src/test/java/io/reactivex/rxjava3/processors/UnicastProcessorTest.java +++ b/src/test/java/io/reactivex/rxjava3/processors/UnicastProcessorTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -25,9 +25,9 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subscribers.TestSubscriber; diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/AbstractSchedulerConcurrencyTests.java b/src/test/java/io/reactivex/rxjava3/schedulers/AbstractSchedulerConcurrencyTests.java index 399a7653052..ae7d1b24b0b 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/AbstractSchedulerConcurrencyTests.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/AbstractSchedulerConcurrencyTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/AbstractSchedulerTests.java b/src/test/java/io/reactivex/rxjava3/schedulers/AbstractSchedulerTests.java index 34d8ac1b39c..2419fe557cc 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/AbstractSchedulerTests.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/AbstractSchedulerTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -27,6 +27,7 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.core.Scheduler.Worker; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.disposables.SequentialDisposable; @@ -771,4 +772,51 @@ public void schedulePeriodicallyDirectNullRunnable() { assertEquals("run is null", npe.getMessage()); } } + + void schedulePrint(Function onSchedule) { + CountDownLatch waitForBody = new CountDownLatch(1); + CountDownLatch waitForPrint = new CountDownLatch(1); + + try { + Disposable d = onSchedule.apply(() -> { + waitForBody.countDown(); + try { + waitForPrint.await(); + } catch (InterruptedException ex) { + ex.printStackTrace(); + } + }); + + waitForBody.await(); + + assertNotEquals("", d.toString()); + } catch (Throwable ex) { + throw new AssertionError(ex); + } finally { + waitForPrint.countDown(); + } + } + + @Test + public void scheduleDirectPrint() { + if (getScheduler() instanceof TrampolineScheduler) { + // no concurrency with Trampoline + return; + } + schedulePrint(r -> getScheduler().scheduleDirect(r)); + } + + @Test + public void schedulePrint() { + if (getScheduler() instanceof TrampolineScheduler) { + // no concurrency with Trampoline + return; + } + Worker worker = getScheduler().createWorker(); + try { + schedulePrint(worker::schedule); + } finally { + worker.dispose(); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/CachedThreadSchedulerTest.java b/src/test/java/io/reactivex/rxjava3/schedulers/CachedThreadSchedulerTest.java index 8782142035e..b4576ebb53c 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/CachedThreadSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/CachedThreadSchedulerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,6 +24,7 @@ import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.schedulers.IoScheduler; +import io.reactivex.rxjava3.testsupport.SuppressUndeliverable; public class CachedThreadSchedulerTest extends AbstractSchedulerConcurrencyTests { @@ -91,6 +92,7 @@ public void workerDisposed() { } @Test + @SuppressUndeliverable public void shutdownRejects() { final int[] calls = { 0 }; diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/ComputationSchedulerTests.java b/src/test/java/io/reactivex/rxjava3/schedulers/ComputationSchedulerTests.java index 0e6248cc890..c88415209d0 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/ComputationSchedulerTests.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/ComputationSchedulerTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -17,14 +17,17 @@ import java.util.HashMap; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; -import io.reactivex.rxjava3.disposables.Disposable; import org.junit.Test; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Scheduler.Worker; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.schedulers.ComputationScheduler; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.testsupport.SuppressUndeliverable; public class ComputationSchedulerTests extends AbstractSchedulerConcurrencyTests { @@ -159,6 +162,7 @@ public void cancelledTaskRetention() throws InterruptedException { } @Test + @SuppressUndeliverable public void shutdownRejects() { final int[] calls = { 0 }; @@ -192,4 +196,129 @@ public void run() { assertEquals(0, calls[0]); } + + @Test + public void exceptionFromObservableShouldNotBeSwallowed() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + + // #3 thread's uncaught exception handler + Scheduler computationScheduler = new ComputationScheduler(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r); + t.setUncaughtExceptionHandler((thread, throwable) -> { + latch.countDown(); + }); + return t; + } + }); + + // #2 RxJava exception handler + RxJavaPlugins.setErrorHandler(h -> { + latch.countDown(); + }); + + // Exceptions, fatal or not, should be handled by + // #1 observer's onError(), or + // #2 RxJava exception handler, or + // #3 thread's uncaught exception handler, + // and should not be swallowed. + try { + + // #1 observer's onError() + Observable.create(s -> { + + s.onNext(1); + throw new OutOfMemoryError(); + }) + .subscribeOn(computationScheduler) + .subscribe(v -> { }, + e -> { latch.countDown(); } + ); + + assertTrue(latch.await(2, TimeUnit.SECONDS)); + } finally { + RxJavaPlugins.reset(); + computationScheduler.shutdown(); + } + } + + @Test + public void exceptionFromObserverShouldNotBeSwallowed() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + + // #3 thread's uncaught exception handler + Scheduler computationScheduler = new ComputationScheduler(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r); + t.setUncaughtExceptionHandler((thread, throwable) -> { + latch.countDown(); + }); + return t; + } + }); + + // #2 RxJava exception handler + RxJavaPlugins.setErrorHandler(h -> { + latch.countDown(); + }); + + // Exceptions, fatal or not, should be handled by + // #1 observer's onError(), or + // #2 RxJava exception handler, or + // #3 thread's uncaught exception handler, + // and should not be swallowed. + try { + + // #1 observer's onError() + Flowable.interval(500, TimeUnit.MILLISECONDS, computationScheduler) + .subscribe(v -> { + throw new OutOfMemoryError(); + }, e -> { + latch.countDown(); + }); + + assertTrue(latch.await(2, TimeUnit.SECONDS)); + } finally { + RxJavaPlugins.reset(); + computationScheduler.shutdown(); + } + } + + @Test + @SuppressUndeliverable + public void periodicTaskShouldStopOnError() throws Exception { + AtomicInteger repeatCount = new AtomicInteger(); + + Schedulers.computation().schedulePeriodicallyDirect(new Runnable() { + @Override + public void run() { + repeatCount.incrementAndGet(); + throw new OutOfMemoryError(); + } + }, 0, 1, TimeUnit.MILLISECONDS); + + Thread.sleep(200); + + assertEquals(1, repeatCount.get()); + } + + @Test + @SuppressUndeliverable + public void periodicTaskShouldStopOnError2() throws Exception { + AtomicInteger repeatCount = new AtomicInteger(); + + Schedulers.computation().schedulePeriodicallyDirect(new Runnable() { + @Override + public void run() { + repeatCount.incrementAndGet(); + throw new OutOfMemoryError(); + } + }, 0, 1, TimeUnit.NANOSECONDS); + + Thread.sleep(200); + + assertEquals(1, repeatCount.get()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/ExecutorSchedulerFairTest.java b/src/test/java/io/reactivex/rxjava3/schedulers/ExecutorSchedulerFairTest.java index 128a3bd5b52..c01f0f9f1fe 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/ExecutorSchedulerFairTest.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/ExecutorSchedulerFairTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/ExecutorSchedulerInterruptibleTest.java b/src/test/java/io/reactivex/rxjava3/schedulers/ExecutorSchedulerInterruptibleTest.java index e9c953b049c..074ac8039a7 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/ExecutorSchedulerInterruptibleTest.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/ExecutorSchedulerInterruptibleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -505,4 +505,609 @@ public void run() { worker.dispose(); } } + + @Test + public void interruptibleDirectTaskScheduledExecutor() throws Exception { + ScheduledExecutorService exec = Executors.newScheduledThreadPool(1); + try { + Scheduler scheduler = Schedulers.from(exec, true); + + final AtomicInteger sync = new AtomicInteger(2); + + final AtomicBoolean isInterrupted = new AtomicBoolean(); + + Disposable d = scheduler.scheduleDirect(new Runnable() { + @Override + public void run() { + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + isInterrupted.set(true); + } + } + }); + + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + + Thread.sleep(500); + + d.dispose(); + + int i = 20; + while (i-- > 0 && !isInterrupted.get()) { + Thread.sleep(50); + } + + assertTrue("Interruption did not propagate", isInterrupted.get()); + } finally { + exec.shutdown(); + } + } + + @Test + public void interruptibleWorkerTaskScheduledExecutor() throws Exception { + ScheduledExecutorService exec = Executors.newScheduledThreadPool(1); + try { + Scheduler scheduler = Schedulers.from(exec, true); + + Worker worker = scheduler.createWorker(); + + try { + final AtomicInteger sync = new AtomicInteger(2); + + final AtomicBoolean isInterrupted = new AtomicBoolean(); + + Disposable d = worker.schedule(new Runnable() { + @Override + public void run() { + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + isInterrupted.set(true); + } + } + }); + + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + + Thread.sleep(500); + + d.dispose(); + + int i = 20; + while (i-- > 0 && !isInterrupted.get()) { + Thread.sleep(50); + } + + assertTrue("Interruption did not propagate", isInterrupted.get()); + } finally { + worker.dispose(); + } + } finally { + exec.shutdown(); + } + } + + @Test + public void nonInterruptibleDirectTask() throws Exception { + ExecutorService exec = Executors.newSingleThreadExecutor(); + try { + Scheduler scheduler = Schedulers.from(exec, false); + + final AtomicInteger sync = new AtomicInteger(2); + + final AtomicBoolean isInterrupted = new AtomicBoolean(); + + Disposable d = scheduler.scheduleDirect(new Runnable() { + @Override + public void run() { + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + isInterrupted.set(true); + } + } + }); + + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + + Thread.sleep(500); + + d.dispose(); + + int i = 20; + while (i-- > 0 && !isInterrupted.get()) { + Thread.sleep(50); + } + + assertFalse("Interruption happened", isInterrupted.get()); + } finally { + exec.shutdown(); + } + } + + @Test + public void nonInterruptibleWorkerTask() throws Exception { + ExecutorService exec = Executors.newSingleThreadExecutor(); + try { + Scheduler scheduler = Schedulers.from(exec, false); + + Worker worker = scheduler.createWorker(); + + try { + final AtomicInteger sync = new AtomicInteger(2); + + final AtomicBoolean isInterrupted = new AtomicBoolean(); + + Disposable d = worker.schedule(new Runnable() { + @Override + public void run() { + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + isInterrupted.set(true); + } + } + }); + + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + + Thread.sleep(500); + + d.dispose(); + + int i = 20; + while (i-- > 0 && !isInterrupted.get()) { + Thread.sleep(50); + } + + assertFalse("Interruption happened", isInterrupted.get()); + } finally { + worker.dispose(); + } + } finally { + exec.shutdown(); + } + } + + @Test + public void nonInterruptibleDirectTaskScheduledExecutor() throws Exception { + ScheduledExecutorService exec = Executors.newScheduledThreadPool(1); + try { + Scheduler scheduler = Schedulers.from(exec, false); + + final AtomicInteger sync = new AtomicInteger(2); + + final AtomicBoolean isInterrupted = new AtomicBoolean(); + + Disposable d = scheduler.scheduleDirect(new Runnable() { + @Override + public void run() { + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + isInterrupted.set(true); + } + } + }); + + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + + Thread.sleep(500); + + d.dispose(); + + int i = 20; + while (i-- > 0 && !isInterrupted.get()) { + Thread.sleep(50); + } + + assertFalse("Interruption happened", isInterrupted.get()); + } finally { + exec.shutdown(); + } + } + + @Test + public void nonInterruptibleWorkerTaskScheduledExecutor() throws Exception { + ScheduledExecutorService exec = Executors.newScheduledThreadPool(1); + try { + Scheduler scheduler = Schedulers.from(exec, false); + + Worker worker = scheduler.createWorker(); + + try { + final AtomicInteger sync = new AtomicInteger(2); + + final AtomicBoolean isInterrupted = new AtomicBoolean(); + + Disposable d = worker.schedule(new Runnable() { + @Override + public void run() { + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + isInterrupted.set(true); + } + } + }); + + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + + Thread.sleep(500); + + d.dispose(); + + int i = 20; + while (i-- > 0 && !isInterrupted.get()) { + Thread.sleep(50); + } + + assertFalse("Interruption happened", isInterrupted.get()); + } finally { + worker.dispose(); + } + } finally { + exec.shutdown(); + } + } + + @Test + public void nonInterruptibleDirectTaskTimed() throws Exception { + ExecutorService exec = Executors.newSingleThreadExecutor(); + try { + Scheduler scheduler = Schedulers.from(exec, false); + + final AtomicInteger sync = new AtomicInteger(2); + + final AtomicBoolean isInterrupted = new AtomicBoolean(); + + Disposable d = scheduler.scheduleDirect(new Runnable() { + @Override + public void run() { + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + isInterrupted.set(true); + } + } + }, 1, TimeUnit.MILLISECONDS); + + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + + Thread.sleep(500); + + d.dispose(); + + int i = 20; + while (i-- > 0 && !isInterrupted.get()) { + Thread.sleep(50); + } + + assertFalse("Interruption happened", isInterrupted.get()); + } finally { + exec.shutdown(); + } + } + + @Test + public void nonInterruptibleWorkerTaskTimed() throws Exception { + ExecutorService exec = Executors.newSingleThreadExecutor(); + try { + Scheduler scheduler = Schedulers.from(exec, false); + + Worker worker = scheduler.createWorker(); + + try { + final AtomicInteger sync = new AtomicInteger(2); + + final AtomicBoolean isInterrupted = new AtomicBoolean(); + + Disposable d = worker.schedule(new Runnable() { + @Override + public void run() { + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + isInterrupted.set(true); + } + } + }, 1, TimeUnit.MILLISECONDS); + + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + + Thread.sleep(500); + + d.dispose(); + + int i = 20; + while (i-- > 0 && !isInterrupted.get()) { + Thread.sleep(50); + } + + assertFalse("Interruption happened", isInterrupted.get()); + } finally { + worker.dispose(); + } + } finally { + exec.shutdown(); + } + } + + @Test + public void nonInterruptibleDirectTaskScheduledExecutorTimed() throws Exception { + ScheduledExecutorService exec = Executors.newScheduledThreadPool(1); + try { + Scheduler scheduler = Schedulers.from(exec, false); + + final AtomicInteger sync = new AtomicInteger(2); + + final AtomicBoolean isInterrupted = new AtomicBoolean(); + + Disposable d = scheduler.scheduleDirect(new Runnable() { + @Override + public void run() { + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + isInterrupted.set(true); + } + } + }, 1, TimeUnit.MILLISECONDS); + + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + + Thread.sleep(500); + + d.dispose(); + + int i = 20; + while (i-- > 0 && !isInterrupted.get()) { + Thread.sleep(50); + } + + assertFalse("Interruption happened", isInterrupted.get()); + } finally { + exec.shutdown(); + } + } + + @Test + public void nonInterruptibleWorkerTaskScheduledExecutorTimed() throws Exception { + ScheduledExecutorService exec = Executors.newScheduledThreadPool(1); + try { + Scheduler scheduler = Schedulers.from(exec, false); + + Worker worker = scheduler.createWorker(); + + try { + final AtomicInteger sync = new AtomicInteger(2); + + final AtomicBoolean isInterrupted = new AtomicBoolean(); + + Disposable d = worker.schedule(new Runnable() { + @Override + public void run() { + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + isInterrupted.set(true); + } + } + }, 1, TimeUnit.MILLISECONDS); + + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + + Thread.sleep(500); + + d.dispose(); + + int i = 20; + while (i-- > 0 && !isInterrupted.get()) { + Thread.sleep(50); + } + + assertFalse("Interruption happened", isInterrupted.get()); + } finally { + worker.dispose(); + } + } finally { + exec.shutdown(); + } + } + + public static class TrackInterruptScheduledExecutor extends ScheduledThreadPoolExecutor { + + public final AtomicBoolean interruptReceived = new AtomicBoolean(); + + public TrackInterruptScheduledExecutor() { + super(10); + } + + @Override + public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { + return new TrackingScheduledFuture(super.schedule(callable, delay, unit)); + } + + class TrackingScheduledFuture implements ScheduledFuture { + + ScheduledFuture original; + + TrackingScheduledFuture(ScheduledFuture original) { + this.original = original; + } + + @Override + public long getDelay(TimeUnit unit) { + return original.getDelay(unit); + } + + @Override + public int compareTo(Delayed o) { + return original.compareTo(o); + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + if (mayInterruptIfRunning) { + interruptReceived.set(true); + } + return original.cancel(mayInterruptIfRunning); + } + + @Override + public boolean isCancelled() { + return original.isCancelled(); + } + + @Override + public boolean isDone() { + return original.isDone(); + } + + @Override + public V get() throws InterruptedException, ExecutionException { + return original.get(); + } + + @Override + public V get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return get(timeout, unit); + } + } + } + + @Test + public void noInterruptBeforeRunningDelayedWorker() throws Throwable { + TrackInterruptScheduledExecutor exec = new TrackInterruptScheduledExecutor(); + + try { + Scheduler sch = Schedulers.from(exec, false); + + Worker worker = sch.createWorker(); + + Disposable d = worker.schedule(() -> { }, 1, TimeUnit.SECONDS); + + d.dispose(); + + int i = 150; + + while (i-- > 0) { + assertFalse("Task interrupt detected", exec.interruptReceived.get()); + Thread.sleep(10); + } + + } finally { + exec.shutdownNow(); + } + } + + @Test + public void hasInterruptBeforeRunningDelayedWorker() throws Throwable { + TrackInterruptScheduledExecutor exec = new TrackInterruptScheduledExecutor(); + + try { + Scheduler sch = Schedulers.from(exec, true); + + Worker worker = sch.createWorker(); + + Disposable d = worker.schedule(() -> { }, 1, TimeUnit.SECONDS); + + d.dispose(); + + Thread.sleep(100); + assertTrue("Task interrupt detected", exec.interruptReceived.get()); + + } finally { + exec.shutdownNow(); + } + } + + @Test + public void noInterruptAfterRunningDelayedWorker() throws Throwable { + TrackInterruptScheduledExecutor exec = new TrackInterruptScheduledExecutor(); + + try { + Scheduler sch = Schedulers.from(exec, false); + + Worker worker = sch.createWorker(); + AtomicBoolean taskRun = new AtomicBoolean(); + + Disposable d = worker.schedule(() -> { + taskRun.set(true); + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + exec.interruptReceived.set(true); + } + }, 100, TimeUnit.MILLISECONDS); + + Thread.sleep(150); + ; + d.dispose(); + + int i = 50; + + while (i-- > 0) { + assertFalse("Task interrupt detected", exec.interruptReceived.get()); + Thread.sleep(10); + } + + assertTrue("Task run at all", taskRun.get()); + + } finally { + exec.shutdownNow(); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/ExecutorSchedulerTest.java b/src/test/java/io/reactivex/rxjava3/schedulers/ExecutorSchedulerTest.java index b2e90cdb00c..bb3e759884c 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/ExecutorSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/ExecutorSchedulerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -18,14 +18,14 @@ import java.lang.management.*; import java.util.List; import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.*; import org.junit.Test; import io.reactivex.rxjava3.core.Scheduler; import io.reactivex.rxjava3.core.Scheduler.Worker; import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.internal.disposables.EmptyDisposable; +import io.reactivex.rxjava3.internal.disposables.*; import io.reactivex.rxjava3.internal.functions.Functions; import io.reactivex.rxjava3.internal.schedulers.*; import io.reactivex.rxjava3.plugins.RxJavaPlugins; @@ -93,7 +93,7 @@ public void run() { System.out.println("Wait before second GC"); System.out.println("JDK 6 purge is N log N because it removes and shifts one by one"); - int t = (int)(n * Math.log(n) / 100) + SchedulerPoolFactory.PURGE_PERIOD_SECONDS * 1000; + int t = (int)(n * Math.log(n) / 100) + 1000; int sleepStep = 100; while (t > 0) { System.out.printf(" >> Waiting for purge: %.2f s remaining%n", t / 1000d); @@ -509,4 +509,42 @@ public void run() { assertSame(Functions.EMPTY_RUNNABLE, wrapper.getWrappedRunnable()); } + + @Test + public void interruptibleRunnableRunDisposeRace() { + ExecutorService exec = Executors.newSingleThreadExecutor(); + try { + Scheduler s = Schedulers.from(r -> exec.execute(r), true); + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + SequentialDisposable sd = new SequentialDisposable(); + + TestHelper.race( + () -> sd.update(s.scheduleDirect(() -> { })), + () -> sd.dispose() + ); + } + } finally { + exec.shutdown(); + } + } + + @Test + public void interruptibleRunnableRunDispose() { + try { + for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { + AtomicReference runRef = new AtomicReference<>(); + Scheduler s = Schedulers.from(r -> { + runRef.set(r); + }, true); + + Disposable d = s.scheduleDirect(() -> { }); + TestHelper.race( + () -> runRef.get().run(), + () -> d.dispose() + ); + } + } finally { + Thread.interrupted(); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/FailOnBlockingTest.java b/src/test/java/io/reactivex/rxjava3/schedulers/FailOnBlockingTest.java index d8891ddc0c5..7cb4c15e073 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/FailOnBlockingTest.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/FailOnBlockingTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/NewThreadSchedulerTest.java b/src/test/java/io/reactivex/rxjava3/schedulers/NewThreadSchedulerTest.java index 352e13333cd..37c7b85f87b 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/NewThreadSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/NewThreadSchedulerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -23,6 +23,7 @@ import io.reactivex.rxjava3.core.Scheduler.Worker; import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.internal.schedulers.NewThreadWorker; +import io.reactivex.rxjava3.testsupport.SuppressUndeliverable; public class NewThreadSchedulerTest extends AbstractSchedulerConcurrencyTests { @@ -37,6 +38,7 @@ public final void handledErrorIsNotDeliveredToThreadHandler() throws Interrupted } @Test + @SuppressUndeliverable public void shutdownRejects() { final int[] calls = { 0 }; @@ -75,6 +77,7 @@ public void run() { * @throws Exception on error */ @Test + @SuppressUndeliverable public void npeRegression() throws Exception { Scheduler s = getScheduler(); NewThreadWorker w = (NewThreadWorker) s.createWorker(); diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerLifecycleTest.java b/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerLifecycleTest.java index c3784482204..58b51254d8a 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerLifecycleTest.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerLifecycleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerTest.java b/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerTest.java index fa97b1c0e7f..a9ec2205a7f 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -61,18 +61,28 @@ public void run() { assertEquals(2, count[0]); } - @Test(expected = TestException.class) - public void periodicDirectThrows() { - TestScheduler scheduler = new TestScheduler(); + @Test + public void periodicDirectThrows() throws Throwable { + TestHelper.withErrorTracking(errors -> { + TestScheduler scheduler = new TestScheduler(); - scheduler.schedulePeriodicallyDirect(new Runnable() { - @Override - public void run() { - throw new TestException(); + try { + scheduler.schedulePeriodicallyDirect(new Runnable() { + @Override + public void run() { + throw new TestException(); + } + }, 100, 100, TimeUnit.MILLISECONDS); + + scheduler.advanceTimeBy(100, TimeUnit.MILLISECONDS); + + fail("Should have thrown!"); + } catch (TestException expected) { + // expected } - }, 100, 100, TimeUnit.MILLISECONDS); - scheduler.advanceTimeBy(100, TimeUnit.MILLISECONDS); + TestHelper.assertUndeliverable(errors, 0, TestException.class); + }); } @Test @@ -233,7 +243,7 @@ public void run() { Thread.sleep(250); - assertEquals(1, list.size()); + assertTrue(list.size() >= 1); TestHelper.assertUndeliverable(list, 0, TestException.class, null); } finally { diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerTestHelper.java b/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerTestHelper.java index 05dda6a058c..3c899f262ec 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerTestHelper.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerTestHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -28,6 +28,8 @@ private SchedulerTestHelper() { /** * Verifies that the given Scheduler does not deliver handled errors to its executing Thread's * {@link java.lang.Thread.UncaughtExceptionHandler}. + * + * @param scheduler {@link Scheduler} to verify. */ static void handledErrorIsNotDeliveredToThreadHandler(Scheduler scheduler) throws InterruptedException { Thread.UncaughtExceptionHandler originalHandler = Thread.getDefaultUncaughtExceptionHandler(); diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerWorkerTest.java b/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerWorkerTest.java index 87ad3698adc..17b7fa5dd76 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerWorkerTest.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/SchedulerWorkerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/TestSchedulerTest.java b/src/test/java/io/reactivex/rxjava3/schedulers/TestSchedulerTest.java index 8bcb1770532..4c2e776e0d9 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/TestSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/TestSchedulerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,6 +30,7 @@ import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava3.internal.util.ExceptionHelper; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.TestScheduler.*; public class TestSchedulerTest extends RxJavaTest { @@ -260,4 +261,95 @@ public void constructorTimeSetsTime() { assertEquals(5, ts.now(TimeUnit.SECONDS)); assertEquals(5000, ts.now(TimeUnit.MILLISECONDS)); } + + @Test + public void withOnScheduleHook() { + AtomicInteger run = new AtomicInteger(); + AtomicInteger counter = new AtomicInteger(); + RxJavaPlugins.setScheduleHandler(r -> { + counter.getAndIncrement(); + return r; + }); + try { + Runnable r = () -> run.getAndIncrement(); + TestScheduler ts = new TestScheduler(true); + + ts.createWorker().schedule(r); + ts.createWorker().schedule(r, 1, TimeUnit.SECONDS); + + ts.advanceTimeBy(1, TimeUnit.SECONDS); + + assertEquals(2, run.get()); + assertEquals(2, counter.get()); + + ts = new TestScheduler(); + + ts.createWorker().schedule(r); + ts.createWorker().schedule(r, 1, TimeUnit.SECONDS); + + ts.advanceTimeBy(1, TimeUnit.SECONDS); + + assertEquals(4, run.get()); + assertEquals(2, counter.get()); + } finally { + RxJavaPlugins.setScheduleHandler(null); + } + } + + @Test + public void withOnScheduleHookInitialTime() { + AtomicInteger run = new AtomicInteger(); + AtomicInteger counter = new AtomicInteger(); + RxJavaPlugins.setScheduleHandler(r -> { + counter.getAndIncrement(); + return r; + }); + try { + Runnable r = () -> run.getAndIncrement(); + TestScheduler ts = new TestScheduler(1, TimeUnit.HOURS, true); + + ts.createWorker().schedule(r); + ts.createWorker().schedule(r, 1, TimeUnit.SECONDS); + + ts.advanceTimeBy(1, TimeUnit.SECONDS); + + assertEquals(2, run.get()); + assertEquals(2, counter.get()); + + ts = new TestScheduler(1, TimeUnit.HOURS); + + ts.createWorker().schedule(r); + ts.createWorker().schedule(r, 1, TimeUnit.SECONDS); + + ts.advanceTimeBy(1, TimeUnit.SECONDS); + + assertEquals(4, run.get()); + assertEquals(2, counter.get()); + } finally { + RxJavaPlugins.setScheduleHandler(null); + } + } + + @Test + public void disposeWork() { + AtomicInteger run = new AtomicInteger(); + Runnable r = () -> run.getAndIncrement(); + TestScheduler ts = new TestScheduler(1, TimeUnit.HOURS, true); + + Disposable d = ts.createWorker().schedule(r); + + assertFalse(d.isDisposed()); + + d.dispose(); + + assertTrue(d.isDisposed()); + + d.dispose(); + + assertTrue(d.isDisposed()); + + ts.advanceTimeBy(1, TimeUnit.SECONDS); + + assertEquals(0, run.get()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/TimedTest.java b/src/test/java/io/reactivex/rxjava3/schedulers/TimedTest.java index d7a5eb752e4..7d82af675e3 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/TimedTest.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/TimedTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -39,7 +39,7 @@ public void hashCodeOf() { assertEquals(TimeUnit.SECONDS.hashCode() + 31 * (5 + 31 * 1), t1.hashCode()); - Timed t2 = new Timed<>(null, 5, TimeUnit.SECONDS); + Timed t2 = new Timed<>(0, 5, TimeUnit.SECONDS); assertEquals(TimeUnit.SECONDS.hashCode() + 31 * (5 + 31 * 0), t2.hashCode()); } diff --git a/src/test/java/io/reactivex/rxjava3/schedulers/TrampolineSchedulerTest.java b/src/test/java/io/reactivex/rxjava3/schedulers/TrampolineSchedulerTest.java index b409aa143af..d98c93a435b 100644 --- a/src/test/java/io/reactivex/rxjava3/schedulers/TrampolineSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava3/schedulers/TrampolineSchedulerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/single/SingleCacheTest.java b/src/test/java/io/reactivex/rxjava3/single/SingleCacheTest.java index 1851c15e1f7..3fe2da558cc 100644 --- a/src/test/java/io/reactivex/rxjava3/single/SingleCacheTest.java +++ b/src/test/java/io/reactivex/rxjava3/single/SingleCacheTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/single/SingleNullTests.java b/src/test/java/io/reactivex/rxjava3/single/SingleNullTests.java index 6ffdb2ebf83..058ecdc6b04 100644 --- a/src/test/java/io/reactivex/rxjava3/single/SingleNullTests.java +++ b/src/test/java/io/reactivex/rxjava3/single/SingleNullTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,6 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.schedulers.Schedulers; public class SingleNullTests extends RxJavaTest { @@ -34,11 +33,6 @@ public class SingleNullTests extends RxJavaTest { Single error = Single.error(new TestException()); - @Test(expected = NullPointerException.class) - public void ambIterableNull() { - Single.amb((Iterable>)null); - } - @Test public void ambIterableIteratorNull() { Single.amb(new Iterable>() { @@ -56,11 +50,6 @@ public void ambIterableOneIsNull() { .assertError(NullPointerException.class); } - @Test(expected = NullPointerException.class) - public void ambArrayNull() { - Single.ambArray((Single[])null); - } - @Test public void ambArrayOneIsNull() { Single.ambArray(null, just1) @@ -68,11 +57,6 @@ public void ambArrayOneIsNull() { .assertError(NullPointerException.class); } - @Test(expected = NullPointerException.class) - public void concatIterableNull() { - Single.concat((Iterable>)null); - } - @Test(expected = NullPointerException.class) public void concatIterableIteratorNull() { Single.concat(new Iterable>() { @@ -88,11 +72,6 @@ public void concatIterableOneIsNull() { Single.concat(Arrays.asList(just1, null)).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void concatObservableNull() { - Single.concat((Flowable>)null); - } - @Test public void concatNull() throws Exception { int maxArgs = 4; @@ -122,41 +101,16 @@ public void concatNull() throws Exception { } } - @Test(expected = NullPointerException.class) - public void createNull() { - Single.unsafeCreate(null); - } - - @Test(expected = NullPointerException.class) - public void deferNull() { - Single.defer(null); - } - @Test(expected = NullPointerException.class) public void deferReturnsNull() { Single.defer(Functions.>nullSupplier()).blockingGet(); } - @Test(expected = NullPointerException.class) - public void errorSupplierNull() { - Single.error((Supplier)null); - } - @Test(expected = NullPointerException.class) public void errorSupplierReturnsNull() { Single.error(Functions.nullSupplier()).blockingGet(); } - @Test(expected = NullPointerException.class) - public void errorNull() { - Single.error((Throwable)null); - } - - @Test(expected = NullPointerException.class) - public void fromCallableNull() { - Single.fromCallable(null); - } - @Test(expected = NullPointerException.class) public void fromCallableReturnsNull() { Single.fromCallable(new Callable() { @@ -167,11 +121,6 @@ public Object call() throws Exception { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void fromFutureNull() { - Single.fromFuture((Future)null); - } - @Test(expected = NullPointerException.class) public void fromFutureReturnsNull() { FutureTask f = new FutureTask<>(Functions.EMPTY_RUNNABLE, null); @@ -179,31 +128,6 @@ public void fromFutureReturnsNull() { Single.fromFuture(f).blockingGet(); } - @Test(expected = NullPointerException.class) - public void fromFutureTimedFutureNull() { - Single.fromFuture(null, 1, TimeUnit.SECONDS); - } - - @Test(expected = NullPointerException.class) - public void fromFutureTimedUnitNull() { - Single.fromFuture(new FutureTask<>(new Callable() { - @Override - public Object call() throws Exception { - return null; - } - }), 1, null); - } - - @Test(expected = NullPointerException.class) - public void fromFutureTimedSchedulerNull() { - Single.fromFuture(new FutureTask<>(new Callable() { - @Override - public Object call() throws Exception { - return null; - } - }), 1, TimeUnit.SECONDS, null); - } - @Test(expected = NullPointerException.class) public void fromFutureTimedReturnsNull() { FutureTask f = new FutureTask<>(Functions.EMPTY_RUNNABLE, null); @@ -211,31 +135,6 @@ public void fromFutureTimedReturnsNull() { Single.fromFuture(f, 1, TimeUnit.SECONDS).blockingGet(); } - @Test(expected = NullPointerException.class) - public void fromFutureSchedulerNull() { - Single.fromFuture(new FutureTask<>(new Callable() { - @Override - public Object call() throws Exception { - return null; - } - }), null); - } - - @Test(expected = NullPointerException.class) - public void fromPublisherNull() { - Single.fromPublisher(null); - } - - @Test(expected = NullPointerException.class) - public void justNull() { - Single.just(null); - } - - @Test(expected = NullPointerException.class) - public void mergeIterableNull() { - Single.merge((Iterable>)null); - } - @Test(expected = NullPointerException.class) public void mergeIterableIteratorNull() { Single.merge(new Iterable>() { @@ -251,11 +150,6 @@ public void mergeIterableOneIsNull() { Single.merge(Arrays.asList(null, just1)).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void mergeSingleNull() { - Single.merge((Single>)null); - } - @Test public void mergeNull() throws Exception { int maxArgs = 4; @@ -285,46 +179,6 @@ public void mergeNull() throws Exception { } } - @Test(expected = NullPointerException.class) - public void timerUnitNull() { - Single.timer(1, null); - } - - @Test(expected = NullPointerException.class) - public void timerSchedulerNull() { - Single.timer(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void equalsFirstNull() { - Single.equals(null, just1); - } - - @Test(expected = NullPointerException.class) - public void equalsSecondNull() { - Single.equals(just1, null); - } - - @Test(expected = NullPointerException.class) - public void usingResourceSupplierNull() { - Single.using(null, new Function>() { - @Override - public Single apply(Object d) { - return just1; - } - }, Functions.emptyConsumer()); - } - - @Test(expected = NullPointerException.class) - public void usingSingleSupplierNull() { - Single.using(new Supplier() { - @Override - public Object get() { - return 1; - } - }, null, Functions.emptyConsumer()); - } - @Test(expected = NullPointerException.class) public void usingSingleSupplierReturnsNull() { Single.using(new Supplier() { @@ -340,31 +194,6 @@ public Single apply(Object d) { }, Functions.emptyConsumer()).blockingGet(); } - @Test(expected = NullPointerException.class) - public void usingDisposeNull() { - Single.using(new Supplier() { - @Override - public Object get() { - return 1; - } - }, new Function>() { - @Override - public Single apply(Object d) { - return just1; - } - }, null); - } - - @Test(expected = NullPointerException.class) - public void zipIterableNull() { - Single.zip((Iterable>)null, new Function() { - @Override - public Object apply(Object[] v) { - return 1; - } - }); - } - @Test(expected = NullPointerException.class) public void zipIterableIteratorNull() { Single.zip(new Iterable>() { @@ -390,11 +219,6 @@ public Object apply(Object[] v) { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void zipIterableOneFunctionNull() { - Single.zip(Arrays.asList(just1, just1), null).blockingGet(); - } - @Test(expected = NullPointerException.class) public void zipIterableOneFunctionReturnsNull() { Single.zip(Arrays.asList(just1, just1), new Function() { @@ -477,51 +301,6 @@ public Object invoke(Object o, Method m1, Object[] a) throws Throwable { } } - @Test(expected = NullPointerException.class) - public void zip2FirstNull() { - Single.zip(null, just1, new BiFunction() { - @Override - public Object apply(Object a, Integer b) { - return 1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void zip2SecondNull() { - Single.zip(just1, null, new BiFunction() { - @Override - public Object apply(Integer a, Object b) { - return 1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void zip2ZipperNull() { - Single.zip(just1, just1, null); - } - - @Test(expected = NullPointerException.class) - public void zip2ZipperReturnsdNull() { - Single.zip(just1, null, new BiFunction() { - @Override - public Object apply(Integer a, Object b) { - return null; - } - }).blockingGet(); - } - - @Test(expected = NullPointerException.class) - public void zipArrayNull() { - Single.zipArray(new Function() { - @Override - public Object apply(Object[] v) { - return 1; - } - }, (Single[])null); - } - @Test(expected = NullPointerException.class) public void zipIterableTwoIsNull() { Single.zip(Arrays.asList(just1, null), new Function() { @@ -544,11 +323,6 @@ public Object apply(Object[] v) { .blockingGet(); } - @Test(expected = NullPointerException.class) - public void zipArrayFunctionNull() { - Single.zipArray(null, just1, just1); - } - @Test(expected = NullPointerException.class) public void zipArrayFunctionReturnsNull() { Single.zipArray(new Function() { @@ -563,61 +337,6 @@ public Object apply(Object[] v) { // Instance methods //************************************************** - @Test(expected = NullPointerException.class) - public void ambWithNull() { - just1.ambWith(null); - } - - @Test(expected = NullPointerException.class) - public void composeNull() { - just1.compose(null); - } - - @Test(expected = NullPointerException.class) - public void castNull() { - just1.cast(null); - } - - @Test(expected = NullPointerException.class) - public void concatWith() { - just1.concatWith(null); - } - - @Test(expected = NullPointerException.class) - public void delayUnitNull() { - just1.delay(1, null); - } - - @Test(expected = NullPointerException.class) - public void delaySchedulerNull() { - just1.delay(1, TimeUnit.SECONDS, null); - } - - @Test(expected = NullPointerException.class) - public void doOnSubscribeNull() { - just1.doOnSubscribe(null); - } - - @Test(expected = NullPointerException.class) - public void doOnSuccess() { - just1.doOnSuccess(null); - } - - @Test(expected = NullPointerException.class) - public void doOnError() { - error.doOnError(null); - } - - @Test(expected = NullPointerException.class) - public void doOnDisposeNull() { - just1.doOnDispose(null); - } - - @Test(expected = NullPointerException.class) - public void flatMapNull() { - just1.flatMap(null); - } - @Test(expected = NullPointerException.class) public void flatMapFunctionReturnsNull() { just1.flatMap(new Function>() { @@ -628,11 +347,6 @@ public Single apply(Integer v) { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void flatMapPublisherNull() { - just1.flatMapPublisher(null); - } - @Test(expected = NullPointerException.class) public void flatMapPublisherFunctionReturnsNull() { just1.flatMapPublisher(new Function>() { @@ -643,11 +357,6 @@ public Publisher apply(Integer v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void liftNull() { - just1.lift(null); - } - @Test(expected = NullPointerException.class) public void liftFunctionReturnsNull() { just1.lift(new SingleOperator() { @@ -658,31 +367,6 @@ public SingleObserver apply(SingleObserver obse }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void containsNull() { - just1.contains(null); - } - - @Test(expected = NullPointerException.class) - public void containsComparerNull() { - just1.contains(1, null); - } - - @Test(expected = NullPointerException.class) - public void mergeWithNull() { - just1.mergeWith(null); - } - - @Test(expected = NullPointerException.class) - public void observeOnNull() { - just1.observeOn(null); - } - - @Test(expected = NullPointerException.class) - public void onErrorReturnSupplierNull() { - just1.onErrorReturn((Function)null); - } - @Test(expected = NullPointerException.class) public void onErrorReturnsSupplierReturnsNull() { error.onErrorReturn(new Function() { @@ -693,21 +377,6 @@ public Integer apply(Throwable t) throws Exception { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void onErrorReturnValueNull() { - error.onErrorReturnItem(null); - } - - @Test(expected = NullPointerException.class) - public void onErrorResumeWithSingleNull() { - error.onErrorResumeWith(null); - } - - @Test(expected = NullPointerException.class) - public void onErrorResumeNextNull() { - error.onErrorResumeNext(null); - } - @Test public void onErrorResumeNextFunctionReturnsNull() { try { @@ -722,11 +391,6 @@ public Single apply(Throwable e) { } } - @Test(expected = NullPointerException.class) - public void repeatWhenNull() { - error.repeatWhen(null); - } - @Test(expected = NullPointerException.class) public void repeatWhenFunctionReturnsNull() { error.repeatWhen(new Function, Publisher>() { @@ -737,26 +401,6 @@ public Publisher apply(Flowable v) { }).blockingSubscribe(); } - @Test(expected = NullPointerException.class) - public void repeatUntilNull() { - error.repeatUntil(null); - } - - @Test(expected = NullPointerException.class) - public void retryBiPreducateNull() { - error.retry((BiPredicate)null); - } - - @Test(expected = NullPointerException.class) - public void retryPredicateNull() { - error.retry((Predicate)null); - } - - @Test(expected = NullPointerException.class) - public void retryWhenNull() { - error.retryWhen(null); - } - @Test(expected = NullPointerException.class) public void retryWhenFunctionReturnsNull() { error.retryWhen(new Function, Publisher>() { @@ -767,21 +411,6 @@ public Publisher apply(Flowable e) { }).blockingGet(); } - @Test(expected = NullPointerException.class) - public void subscribeBiConsumerNull() { - just1.subscribe((BiConsumer)null); - } - - @Test(expected = NullPointerException.class) - public void subscribeConsumerNull() { - just1.subscribe((Consumer)null); - } - - @Test(expected = NullPointerException.class) - public void subscribeSingeSubscriberNull() { - just1.subscribe((SingleObserver)null); - } - @Test(expected = NullPointerException.class) public void subscribeOnSuccessNull() { just1.subscribe(null, new Consumer() { @@ -790,64 +419,6 @@ public void accept(Throwable e) { } }); } - @Test(expected = NullPointerException.class) - public void subscribeOnErrorNull() { - just1.subscribe(new Consumer() { - @Override - public void accept(Integer v) { } - }, null); - } - - @Test(expected = NullPointerException.class) - public void subscribeSubscriberNull() { - just1.toFlowable().subscribe((Subscriber)null); - } - - @Test(expected = NullPointerException.class) - public void subscribeOnNull() { - just1.subscribeOn(null); - } - - @Test(expected = NullPointerException.class) - public void timeoutUnitNull() { - just1.timeout(1, null); - } - - @Test(expected = NullPointerException.class) - public void timeoutSchedulerNull() { - just1.timeout(1, TimeUnit.SECONDS, (Scheduler)null); - } - - @Test(expected = NullPointerException.class) - public void timeoutOtherNull() { - just1.timeout(1, TimeUnit.SECONDS, Schedulers.single(), null); - } - - @Test(expected = NullPointerException.class) - public void timeoutOther2Null() { - just1.timeout(1, TimeUnit.SECONDS, (Single)null); - } - - @Test(expected = NullPointerException.class) - public void toNull() { - just1.to(null); - } - - @Test(expected = NullPointerException.class) - public void zipWithNull() { - just1.zipWith(null, new BiFunction() { - @Override - public Object apply(Integer a, Object b) { - return 1; - } - }); - } - - @Test(expected = NullPointerException.class) - public void zipWithFunctionNull() { - just1.zipWith(just1, null); - } - @Test(expected = NullPointerException.class) public void zipWithFunctionReturnsNull() { just1.zipWith(just1, new BiFunction() { diff --git a/src/test/java/io/reactivex/rxjava3/single/SingleRetryTest.java b/src/test/java/io/reactivex/rxjava3/single/SingleRetryTest.java index 1d5a1bff33b..e38322a4abc 100644 --- a/src/test/java/io/reactivex/rxjava3/single/SingleRetryTest.java +++ b/src/test/java/io/reactivex/rxjava3/single/SingleRetryTest.java @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2017-present, RxJava Contributors. +/* + * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at @@ -21,6 +21,7 @@ import org.junit.Test; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Predicate; import io.reactivex.rxjava3.internal.functions.Functions; @@ -120,4 +121,42 @@ public void retryTimesPredicateWithZeroRetries() { assertEquals(1, numberOfSubscribeCalls.get()); } + + @Test + public void untilTrueJust() { + Single.just(1) + .retryUntil(() -> true) + .test() + .assertResult(1); + } + + @Test + public void untilFalseJust() { + Single.just(1) + .retryUntil(() -> false) + .test() + .assertResult(1); + } + + @Test + public void untilTrueError() { + Single.error(new TestException()) + .retryUntil(() -> true) + .test() + .assertFailure(TestException.class); + } + + @Test + public void untilFalseError() { + AtomicInteger counter = new AtomicInteger(); + Single.defer(() -> { + if (counter.getAndIncrement() == 0) { + return Single.error(new TestException()); + } + return Single.just(1); + }) + .retryUntil(() -> false) + .test() + .assertResult(1); + } } diff --git a/src/test/java/io/reactivex/rxjava3/single/SingleSubscribeTest.java b/src/test/java/io/reactivex/rxjava3/single/SingleSubscribeTest.java index 68484d63c1f..df363bee830 100644 --- a/src/test/java/io/reactivex/rxjava3/single/SingleSubscribeTest.java +++ b/src/test/java/io/reactivex/rxjava3/single/SingleSubscribeTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/single/SingleTest.java b/src/test/java/io/reactivex/rxjava3/single/SingleTest.java index 1f7cba7e2d2..7b51c97471d 100644 --- a/src/test/java/io/reactivex/rxjava3/single/SingleTest.java +++ b/src/test/java/io/reactivex/rxjava3/single/SingleTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/single/SingleTimerTest.java b/src/test/java/io/reactivex/rxjava3/single/SingleTimerTest.java index c8624b710a9..7fefa15467f 100644 --- a/src/test/java/io/reactivex/rxjava3/single/SingleTimerTest.java +++ b/src/test/java/io/reactivex/rxjava3/single/SingleTimerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/subjects/AsyncSubjectTest.java b/src/test/java/io/reactivex/rxjava3/subjects/AsyncSubjectTest.java index 395300e2923..8228b74b5d2 100644 --- a/src/test/java/io/reactivex/rxjava3/subjects/AsyncSubjectTest.java +++ b/src/test/java/io/reactivex/rxjava3/subjects/AsyncSubjectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -24,11 +24,11 @@ import org.mockito.*; import io.reactivex.rxjava3.core.Observer; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.Consumer; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.testsupport.*; public class AsyncSubjectTest extends SubjectTest { @@ -112,6 +112,7 @@ public void subscribeAfterError() { } @Test + @SuppressUndeliverable public void error() { AsyncSubject subject = AsyncSubject.create(); @@ -418,6 +419,7 @@ public void run() { } @Test + @SuppressUndeliverable public void onErrorCancelRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { @@ -475,6 +477,7 @@ public void onNext(Object t) { } @Test + @SuppressUndeliverable public void onErrorCrossCancel() { AsyncSubject p = AsyncSubject.create(); @@ -517,4 +520,9 @@ public void onComplete() { to1.assertResult(); to2.assertEmpty(); } + + @Test + public void dispose() { + TestHelper.checkDisposed(AsyncSubject.create()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/subjects/BehaviorSubjectTest.java b/src/test/java/io/reactivex/rxjava3/subjects/BehaviorSubjectTest.java index 8e472ec4c5f..8871ee8e7ee 100644 --- a/src/test/java/io/reactivex/rxjava3/subjects/BehaviorSubjectTest.java +++ b/src/test/java/io/reactivex/rxjava3/subjects/BehaviorSubjectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -833,4 +833,19 @@ public void emittingEmitNext() { assertNotNull(bd.queue); } + + @Test + public void hasObservers() { + BehaviorSubject bs = BehaviorSubject.create(); + + assertFalse(bs.hasObservers()); + + TestObserver to = bs.test(); + + assertTrue(bs.hasObservers()); + + to.dispose(); + + assertFalse(bs.hasObservers()); + } } diff --git a/src/test/java/io/reactivex/rxjava3/subjects/CompletableSubjectTest.java b/src/test/java/io/reactivex/rxjava3/subjects/CompletableSubjectTest.java index 02ac92b064a..6b5a7a6085c 100644 --- a/src/test/java/io/reactivex/rxjava3/subjects/CompletableSubjectTest.java +++ b/src/test/java/io/reactivex/rxjava3/subjects/CompletableSubjectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/subjects/MaybeSubjectTest.java b/src/test/java/io/reactivex/rxjava3/subjects/MaybeSubjectTest.java index 31742e10a9e..c741f025088 100644 --- a/src/test/java/io/reactivex/rxjava3/subjects/MaybeSubjectTest.java +++ b/src/test/java/io/reactivex/rxjava3/subjects/MaybeSubjectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/subjects/PublishSubjectTest.java b/src/test/java/io/reactivex/rxjava3/subjects/PublishSubjectTest.java index 7c2c333a2ba..a4b464c5129 100644 --- a/src/test/java/io/reactivex/rxjava3/subjects/PublishSubjectTest.java +++ b/src/test/java/io/reactivex/rxjava3/subjects/PublishSubjectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -29,7 +29,7 @@ import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.observers.*; -import io.reactivex.rxjava3.testsupport.TestHelper; +import io.reactivex.rxjava3.testsupport.*; public class PublishSubjectTest extends SubjectTest { @@ -39,6 +39,7 @@ protected Subject create() { } @Test + @SuppressUndeliverable public void completed() { PublishSubject subject = PublishSubject.create(); @@ -112,6 +113,7 @@ private void assertCompletedSubscriber(Observer observer) { } @Test + @SuppressUndeliverable public void error() { PublishSubject subject = PublishSubject.create(); @@ -414,6 +416,7 @@ public void onNext(Integer t) { } @Test + @SuppressUndeliverable public void crossCancelOnError() { final TestObserver to1 = new TestObserver<>(); TestObserver to2 = new TestObserver() { diff --git a/src/test/java/io/reactivex/rxjava3/subjects/ReplaySubjectBoundedConcurrencyTest.java b/src/test/java/io/reactivex/rxjava3/subjects/ReplaySubjectBoundedConcurrencyTest.java index 369fcfc59fd..419e5c92a96 100644 --- a/src/test/java/io/reactivex/rxjava3/subjects/ReplaySubjectBoundedConcurrencyTest.java +++ b/src/test/java/io/reactivex/rxjava3/subjects/ReplaySubjectBoundedConcurrencyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/subjects/ReplaySubjectConcurrencyTest.java b/src/test/java/io/reactivex/rxjava3/subjects/ReplaySubjectConcurrencyTest.java index 767553dc599..454b56e515e 100644 --- a/src/test/java/io/reactivex/rxjava3/subjects/ReplaySubjectConcurrencyTest.java +++ b/src/test/java/io/reactivex/rxjava3/subjects/ReplaySubjectConcurrencyTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/subjects/ReplaySubjectTest.java b/src/test/java/io/reactivex/rxjava3/subjects/ReplaySubjectTest.java index eb06a1a0eaa..8417b530819 100644 --- a/src/test/java/io/reactivex/rxjava3/subjects/ReplaySubjectTest.java +++ b/src/test/java/io/reactivex/rxjava3/subjects/ReplaySubjectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -44,6 +44,7 @@ protected Subject create() { } @Test + @SuppressUndeliverable public void completed() { ReplaySubject subject = ReplaySubject.create(); @@ -68,6 +69,7 @@ public void completed() { } @Test + @SuppressUndeliverable public void completedStopsEmittingData() { ReplaySubject channel = ReplaySubject.create(); Observer observerA = TestHelper.mockObserver(); @@ -137,6 +139,7 @@ public void completedStopsEmittingData() { } @Test + @SuppressUndeliverable public void completedAfterError() { ReplaySubject subject = ReplaySubject.create(); @@ -167,6 +170,7 @@ private void assertCompletedSubscriber(Observer observer) { } @Test + @SuppressUndeliverable public void error() { ReplaySubject subject = ReplaySubject.create(); @@ -797,6 +801,7 @@ public void getValuesUnbounded() { } + @Test public void createInvalidCapacity() { try { ReplaySubject.create(-99); @@ -1373,4 +1378,70 @@ public void timeAndSizeRemoveCorrectNumberOfOld() { rs.test().assertValuesOnly(4, 5); } + + @Test + public void terminationSubscriptionRaceUnbounded() throws Throwable { + for (int i = 1; i <= 10000; i++) { + Subject source = ReplaySubject.create(); + Subject sink = PublishSubject.create(); + TestObserver observer = sink.test(); + Schedulers.computation().scheduleDirect(() -> { + // issue signals to the source in adherence to the reactive streams specification + source.onSubscribe(Disposable.empty()); + source.onNext("hello"); + source.onNext("world"); + source.onComplete(); + }); + Schedulers.computation().scheduleDirect(() -> { + // connect the source to the sink in parallel with the signals issued to the source + // note the cast() operator, which is here to detect non-String escapees + source.cast(String.class).subscribe(sink); + }); + observer.await().assertValues("hello", "world").assertComplete(); + } + } + + @Test + public void terminationSubscriptionRaceSizeBound() throws Throwable { + for (int i = 1; i <= 10000; i++) { + Subject source = ReplaySubject.createWithSize(20); + Subject sink = PublishSubject.create(); + TestObserver observer = sink.test(); + Schedulers.computation().scheduleDirect(() -> { + // issue signals to the source in adherence to the reactive streams specification + source.onSubscribe(Disposable.empty()); + source.onNext("hello"); + source.onNext("world"); + source.onComplete(); + }); + Schedulers.computation().scheduleDirect(() -> { + // connect the source to the sink in parallel with the signals issued to the source + // note the cast() operator, which is here to detect non-String escapees + source.cast(String.class).subscribe(sink); + }); + observer.await().assertValues("hello", "world").assertComplete(); + } + } + + @Test + public void terminationSubscriptionRaceTimeBound() throws Throwable { + for (int i = 1; i <= 10000; i++) { + Subject source = ReplaySubject.createWithTime(20, TimeUnit.MINUTES, Schedulers.computation()); + Subject sink = PublishSubject.create(); + TestObserver observer = sink.test(); + Schedulers.computation().scheduleDirect(() -> { + // issue signals to the source in adherence to the reactive streams specification + source.onSubscribe(Disposable.empty()); + source.onNext("hello"); + source.onNext("world"); + source.onComplete(); + }); + Schedulers.computation().scheduleDirect(() -> { + // connect the source to the sink in parallel with the signals issued to the source + // note the cast() operator, which is here to detect non-String escapees + source.cast(String.class).subscribe(sink); + }); + observer.await().assertValues("hello", "world").assertComplete(); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/subjects/SerializedSubjectTest.java b/src/test/java/io/reactivex/rxjava3/subjects/SerializedSubjectTest.java index bf74ac5998b..18ff5033392 100644 --- a/src/test/java/io/reactivex/rxjava3/subjects/SerializedSubjectTest.java +++ b/src/test/java/io/reactivex/rxjava3/subjects/SerializedSubjectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,9 +20,10 @@ import org.junit.Test; +import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.RxJavaTest; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.observers.TestObserver; import io.reactivex.rxjava3.plugins.RxJavaPlugins; @@ -665,4 +666,51 @@ public void run() { to.assertEmpty(); } } + + @Test + public void onErrorQueued() { + Subject sp = PublishSubject.create().toSerialized(); + + TestObserver to = new TestObserver() { + @Override + public void onNext(@NonNull Integer t) { + super.onNext(t); + if (t == 1) { + sp.onNext(2); + sp.onNext(3); + sp.onSubscribe(Disposable.empty()); + sp.onError(new TestException()); + } + } + }; + + sp.subscribe(to); + + sp.onNext(1); + + to.assertFailure(TestException.class, 1); // errors skip ahead + } + + @Test + public void onCompleteQueued() { + Subject sp = PublishSubject.create().toSerialized(); + + TestObserver to = new TestObserver() { + @Override + public void onNext(@NonNull Integer t) { + super.onNext(t); + if (t == 1) { + sp.onNext(2); + sp.onNext(3); + sp.onComplete(); + } + } + }; + + sp.subscribe(to); + + sp.onNext(1); + + to.assertResult(1, 2, 3); + } } diff --git a/src/test/java/io/reactivex/rxjava3/subjects/SingleSubjectTest.java b/src/test/java/io/reactivex/rxjava3/subjects/SingleSubjectTest.java index 521fb77fe47..751f0c72d4b 100644 --- a/src/test/java/io/reactivex/rxjava3/subjects/SingleSubjectTest.java +++ b/src/test/java/io/reactivex/rxjava3/subjects/SingleSubjectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/subjects/SubjectTest.java b/src/test/java/io/reactivex/rxjava3/subjects/SubjectTest.java index ab22d10a0c0..ce7177a58d4 100644 --- a/src/test/java/io/reactivex/rxjava3/subjects/SubjectTest.java +++ b/src/test/java/io/reactivex/rxjava3/subjects/SubjectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/subjects/UnicastSubjectTest.java b/src/test/java/io/reactivex/rxjava3/subjects/UnicastSubjectTest.java index ac000e4228e..8ae618319b8 100644 --- a/src/test/java/io/reactivex/rxjava3/subjects/UnicastSubjectTest.java +++ b/src/test/java/io/reactivex/rxjava3/subjects/UnicastSubjectTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,8 +26,8 @@ import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.testsupport.*; @@ -481,9 +481,7 @@ public void fusedNoConcurrentCleanDueToCancel() { us.onNext(i); } - to - .awaitDone(5, TimeUnit.SECONDS) - ; + to.awaitDone(10, TimeUnit.SECONDS); if (!errors.isEmpty()) { throw new CompositeException(errors); @@ -495,4 +493,20 @@ public void fusedNoConcurrentCleanDueToCancel() { } } } + + @Test + public void withCapacityHint() { + UnicastSubject us = UnicastSubject.create(16); + + TestObserver to = us.test(); + + for (int i = 0; i < 256; i++) { + us.onNext(i); + } + us.onComplete(); + + to.assertValueCount(256) + .assertComplete() + .assertNoErrors(); + } } diff --git a/src/test/java/io/reactivex/rxjava3/subscribers/DefaultSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/subscribers/DefaultSubscriberTest.java index 562759247c9..b68a6fe695f 100644 --- a/src/test/java/io/reactivex/rxjava3/subscribers/DefaultSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/subscribers/DefaultSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/subscribers/DisposableSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/subscribers/DisposableSubscriberTest.java index b58b2314673..6aa5c1ff519 100644 --- a/src/test/java/io/reactivex/rxjava3/subscribers/DisposableSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/subscribers/DisposableSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/subscribers/ResourceSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/subscribers/ResourceSubscriberTest.java index 5b135a6ed20..6bbc127cda3 100644 --- a/src/test/java/io/reactivex/rxjava3/subscribers/ResourceSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/subscribers/ResourceSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/subscribers/SafeSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/subscribers/SafeSubscriberTest.java index e2bc1b1bbd5..cd97fa11a32 100644 --- a/src/test/java/io/reactivex/rxjava3/subscribers/SafeSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/subscribers/SafeSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -98,6 +98,7 @@ public void onNextAfterOnCompleted() { * Ensure onError can not be called after onComplete. */ @Test + @SuppressUndeliverable public void onErrorAfterOnCompleted() { TestObservable t = new TestObservable(); Flowable st = Flowable.unsafeCreate(t); @@ -364,6 +365,7 @@ public void dispose() { } @Test + @SuppressUndeliverable public void onNextAfterComplete() { TestSubscriber ts = new TestSubscriber<>(); diff --git a/src/test/java/io/reactivex/rxjava3/subscribers/SerializedSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/subscribers/SerializedSubscriberTest.java index 00c7ae21038..2402762d939 100644 --- a/src/test/java/io/reactivex/rxjava3/subscribers/SerializedSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/subscribers/SerializedSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -341,11 +341,11 @@ public void onNext(String t) { * * When using SynchronizedSubscriber we get this output: * - * p1: 18 p2: 68 => should be close to each other unless we have thread starvation + * {@code p1: 18 p2: 68 =>} should be close to each other unless we have thread starvation * * When using SerializedSubscriber we get: * - * p1: 1 p2: 2445261 => should be close to each other unless we have thread starvation + * {@code p1: 1 p2: 2445261 =>} should be close to each other unless we have thread starvation * * This demonstrates how SynchronizedSubscriber balances back and forth better, and blocks emission. * The real issue in this example is the async buffer-bloat, so we need backpressure. @@ -1134,4 +1134,29 @@ public void nullOnNext() { ts.assertFailureAndMessage(NullPointerException.class, ExceptionHelper.nullWarning("onNext called with a null value.")); } + + @Test + @SuppressUndeliverable + public void onErrorQueuedUp() { + AtomicReference> ssRef = new AtomicReference<>(); + TestSubscriberEx ts = new TestSubscriberEx() { + @Override + public void onNext(Integer t) { + super.onNext(t); + ssRef.get().onNext(2); + ssRef.get().onError(new TestException()); + } + }; + + final SerializedSubscriber so = new SerializedSubscriber<>(ts, true); + ssRef.set(so); + + BooleanSubscription bs = new BooleanSubscription(); + + so.onSubscribe(bs); + + so.onNext(1); + + ts.assertFailure(TestException.class, 1, 2); + } } diff --git a/src/test/java/io/reactivex/rxjava3/subscribers/TestSubscriberTest.java b/src/test/java/io/reactivex/rxjava3/subscribers/TestSubscriberTest.java index 6127d31ff51..40bdcb95cc0 100644 --- a/src/test/java/io/reactivex/rxjava3/subscribers/TestSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava3/subscribers/TestSubscriberTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,8 +21,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import org.junit.*; -import org.junit.rules.ExpectedException; +import org.junit.Test; +import org.junit.function.ThrowingRunnable; import org.mockito.InOrder; import org.reactivestreams.*; @@ -38,9 +38,6 @@ public class TestSubscriberTest extends RxJavaTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void assertTestSubscriber() { Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); @@ -55,53 +52,47 @@ public void assertTestSubscriber() { @Test public void assertNotMatchCount() { - Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); - TestSubscriber ts = new TestSubscriber<>(); - oi.subscribe(ts); + assertThrows(AssertionError.class, () -> { + Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); + TestSubscriber ts = new TestSubscriber<>(); + oi.subscribe(ts); - thrown.expect(AssertionError.class); - // FIXME different message pattern - // thrown.expectMessage("Number of items does not match. Provided: 1 Actual: 2"); - - ts.assertValues(1); - ts.assertValueCount(2); - ts.assertComplete(); - ts.assertNoErrors(); + ts.assertValues(1); + ts.assertValueCount(2); + ts.assertComplete(); + ts.assertNoErrors(); + }); } @Test public void assertNotMatchValue() { - Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); - TestSubscriber ts = new TestSubscriber<>(); - oi.subscribe(ts); + assertThrows(AssertionError.class, () -> { + Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); + TestSubscriber ts = new TestSubscriber<>(); + oi.subscribe(ts); - thrown.expect(AssertionError.class); - // FIXME different message pattern - // thrown.expectMessage("Value at index: 1 expected to be [3] (Integer) but was: [2] (Integer)"); - - ts.assertValues(1, 3); - ts.assertValueCount(2); - ts.assertComplete(); - ts.assertNoErrors(); + ts.assertValues(1, 3); + ts.assertValueCount(2); + ts.assertComplete(); + ts.assertNoErrors(); + }); } @Test public void assertTerminalEventNotReceived() { - PublishProcessor p = PublishProcessor.create(); - TestSubscriber ts = new TestSubscriber<>(); - p.subscribe(ts); - - p.onNext(1); - p.onNext(2); + assertThrows(AssertionError.class, () -> { + PublishProcessor p = PublishProcessor.create(); + TestSubscriber ts = new TestSubscriber<>(); + p.subscribe(ts); - thrown.expect(AssertionError.class); - // FIXME different message pattern - // thrown.expectMessage("No terminal events received."); + p.onNext(1); + p.onNext(2); - ts.assertValues(1, 2); - ts.assertValueCount(2); - ts.assertComplete(); - ts.assertNoErrors(); + ts.assertValues(1, 2); + ts.assertValueCount(2); + ts.assertComplete(); + ts.assertNoErrors(); + }); } @Test @@ -1375,16 +1366,16 @@ public void onComplete() { @Test public void assertValuePredicateEmpty() { - TestSubscriber ts = new TestSubscriber<>(); + assertThrows(AssertionError.class, () -> { + TestSubscriber ts = new TestSubscriber<>(); - Flowable.empty().subscribe(ts); + Flowable.empty().subscribe(ts); - thrown.expect(AssertionError.class); - thrown.expectMessage("No values"); - ts.assertValue(new Predicate() { - @Override public boolean test(final Object o) throws Exception { - return false; - } + ts.assertValue(new Predicate() { + @Override public boolean test(final Object o) throws Exception { + return false; + } + }); }); } @@ -1401,48 +1392,52 @@ public void assertValuePredicateMatch() { }); } + static void assertThrowsWithMessage(String message, Class clazz, ThrowingRunnable run) { + assertEquals(message, assertThrows(clazz, run).getMessage()); + } + @Test public void assertValuePredicateNoMatch() { - TestSubscriber ts = new TestSubscriber<>(); + assertThrowsWithMessage("Value 1 (class: Integer) at position 0 did not pass the predicate (latch = 0, values = 1, errors = 0, completions = 1)", AssertionError.class, () -> { + TestSubscriber ts = new TestSubscriber<>(); - Flowable.just(1).subscribe(ts); + Flowable.just(1).subscribe(ts); - thrown.expect(AssertionError.class); - thrown.expectMessage("Value not present"); - ts.assertValue(new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o != 1; - } + ts.assertValue(new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o != 1; + } + }); }); } @Test public void assertValuePredicateMatchButMore() { - TestSubscriber ts = new TestSubscriber<>(); + assertThrowsWithMessage("The first value passed the predicate but this consumer received more than one value (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + TestSubscriber ts = new TestSubscriber<>(); - Flowable.just(1, 2).subscribe(ts); + Flowable.just(1, 2).subscribe(ts); - thrown.expect(AssertionError.class); - thrown.expectMessage("Value present but other values as well"); - ts.assertValue(new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o == 1; - } + ts.assertValue(new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o == 1; + } + }); }); } @Test public void assertValueAtPredicateEmpty() { - TestSubscriber ts = new TestSubscriber<>(); + assertThrowsWithMessage("No values (latch = 0, values = 0, errors = 0, completions = 1)", AssertionError.class, () -> { + TestSubscriber ts = new TestSubscriber<>(); - Flowable.empty().subscribe(ts); + Flowable.empty().subscribe(ts); - thrown.expect(AssertionError.class); - thrown.expectMessage("No values"); - ts.assertValueAt(0, new Predicate() { - @Override public boolean test(final Object o) throws Exception { - return false; - } + ts.assertValueAt(0, new Predicate() { + @Override public boolean test(final Object o) throws Exception { + return false; + } + }); }); } @@ -1461,31 +1456,68 @@ public void assertValueAtPredicateMatch() { @Test public void assertValueAtPredicateNoMatch() { - TestSubscriber ts = new TestSubscriber<>(); + assertThrowsWithMessage("Value 3 (class: Integer) at position 2 did not pass the predicate (latch = 0, values = 3, errors = 0, completions = 1)", AssertionError.class, () -> { + TestSubscriber ts = new TestSubscriber<>(); - Flowable.just(1, 2, 3).subscribe(ts); + Flowable.just(1, 2, 3).subscribe(ts); - thrown.expect(AssertionError.class); - thrown.expectMessage("Value not present"); - ts.assertValueAt(2, new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o != 3; - } + ts.assertValueAt(2, new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o != 3; + } + }); }); } @Test public void assertValueAtInvalidIndex() { - TestSubscriber ts = new TestSubscriber<>(); + assertThrowsWithMessage("Index 2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + TestSubscriber ts = new TestSubscriber<>(); - Flowable.just(1, 2).subscribe(ts); + Flowable.just(1, 2).subscribe(ts); - thrown.expect(AssertionError.class); - thrown.expectMessage("Invalid index: 2 (latch = 0, values = 2, errors = 0, completions = 1)"); - ts.assertValueAt(2, new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o == 1; - } + ts.assertValueAt(2, new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o == 1; + } + }); + }); + } + + @Test + public void assertValueAtIndexInvalidIndex() { + assertThrowsWithMessage("Index 2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.just(1, 2).subscribe(ts); + + ts.assertValueAt(2, 3); + }); + } + + @Test + public void assertValueAtIndexInvalidIndexNegative() { + assertThrowsWithMessage("Index -2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.just(1, 2).subscribe(ts); + + ts.assertValueAt(-2, 3); + }); + } + + @Test + public void assertValueAtInvalidIndexNegative() { + assertThrowsWithMessage("Index -2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + TestSubscriber ts = new TestSubscriber<>(); + + Flowable.just(1, 2).subscribe(ts); + + ts.assertValueAt(-2, new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o == 1; + } + }); }); } @@ -1671,4 +1703,40 @@ public void assertValuesOnlyThrowsWhenErrored() { // expected } } + + @Test + public void onErrorIsNull() { + TestSubscriber ts = TestSubscriber.create(); + ts.onSubscribe(new BooleanSubscription()); + + ts.onError(null); + + ts.assertFailure(NullPointerException.class); + } + + static final class TestSubscriberImpl extends TestSubscriber { + public boolean isTimeout() { + return timeout; + } + } + + @Test + public void awaitCountTimeout() { + TestSubscriberImpl ts = new TestSubscriberImpl<>(); + ts.onSubscribe(new BooleanSubscription()); + ts.awaitCount(1); + assertTrue(ts.isTimeout()); + } + + @Test(expected = RuntimeException.class) + public void awaitCountInterrupted() { + try { + TestSubscriber ts = TestSubscriber.create(); + ts.onSubscribe(new BooleanSubscription()); + Thread.currentThread().interrupt(); + ts.awaitCount(1); + } finally { + Thread.interrupted(); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/tck/AllTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/AllTckTest.java index 5d2ce5eed98..4b8060fba92 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/AllTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/AllTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/AmbArrayTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/AmbArrayTckTest.java index 88b24a00abf..1260dd2d582 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/AmbArrayTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/AmbArrayTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/AmbTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/AmbTckTest.java index a0d4a637644..6c687b7461b 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/AmbTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/AmbTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/AnyTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/AnyTckTest.java index 5d93dd54625..34e9fe55178 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/AnyTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/AnyTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/AsyncProcessorAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/AsyncProcessorAsPublisherTckTest.java index 87dd4afb336..87a75f00529 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/AsyncProcessorAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/AsyncProcessorAsPublisherTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/BaseTck.java b/src/test/java/io/reactivex/rxjava3/tck/BaseTck.java index 82c25e95919..aa42bcc03a0 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/BaseTck.java +++ b/src/test/java/io/reactivex/rxjava3/tck/BaseTck.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -51,7 +51,7 @@ public long maxElementsFromPublisher() { /** * Creates an Iterable with the specified number of elements or an infinite one if - * elements > {@link Integer#MAX_VALUE}. + * {@code elements >} {@link Integer#MAX_VALUE}. * @param elements the number of elements to return, {@link Integer#MAX_VALUE} means an infinite sequence * @return the Iterable */ diff --git a/src/test/java/io/reactivex/rxjava3/tck/BehaviorProcessorAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/BehaviorProcessorAsPublisherTckTest.java index 219a8ab1a25..94c5e15c140 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/BehaviorProcessorAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/BehaviorProcessorAsPublisherTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/BufferBoundaryTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/BufferBoundaryTckTest.java index 18a6fe4a21e..cf79b210d6b 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/BufferBoundaryTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/BufferBoundaryTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/BufferExactSizeTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/BufferExactSizeTckTest.java index 5af053e052c..d4b7a7abf57 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/BufferExactSizeTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/BufferExactSizeTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/CacheTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/CacheTckTest.java index 460fb80e70e..ec9c481fdc0 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/CacheTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/CacheTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/CollectTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/CollectTckTest.java index fe09c2f061d..76c359f3273 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/CollectTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/CollectTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/CombineLatestArrayDelayErrorTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/CombineLatestArrayDelayErrorTckTest.java index dcb5a94fe6c..80bccac2733 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/CombineLatestArrayDelayErrorTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/CombineLatestArrayDelayErrorTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,7 @@ public class CombineLatestArrayDelayErrorTckTest extends BaseTck { @Override public Publisher createPublisher(long elements) { return - Flowable.combineLatestDelayError( + Flowable.combineLatestArrayDelayError( new Publisher[] { Flowable.just(1L), Flowable.fromIterable(iterate(elements)) }, new Function() { @Override diff --git a/src/test/java/io/reactivex/rxjava3/tck/CombineLatestArrayTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/CombineLatestArrayTckTest.java index 2cebfe655b0..c5a040dc255 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/CombineLatestArrayTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/CombineLatestArrayTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/CombineLatestIterableDelayErrorTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/CombineLatestIterableDelayErrorTckTest.java index 5581b9551ee..41883ab6c1b 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/CombineLatestIterableDelayErrorTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/CombineLatestIterableDelayErrorTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/CombineLatestIterableTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/CombineLatestIterableTckTest.java index 744d9099492..a7b9279a569 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/CombineLatestIterableTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/CombineLatestIterableTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/CompletableAndThenPublisherTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/CompletableAndThenPublisherTckTest.java index 9e9eae893d3..22c1d4ceef3 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/CompletableAndThenPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/CompletableAndThenPublisherTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ConcatArrayEagerTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ConcatArrayEagerTckTest.java index 9885f3b939e..25afb450605 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ConcatArrayEagerTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ConcatArrayEagerTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ConcatIterableEagerTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ConcatIterableEagerTckTest.java index e3654184499..491f211cc20 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ConcatIterableEagerTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ConcatIterableEagerTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ConcatMapIterableTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ConcatMapIterableTckTest.java index 43dcb2cf20c..1a5ab461930 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ConcatMapIterableTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ConcatMapIterableTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ConcatMapMaybeTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ConcatMapMaybeTckTest.java index f01d8ec5115..5216b6a50f1 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ConcatMapMaybeTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ConcatMapMaybeTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ConcatMapSingleTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ConcatMapSingleTckTest.java index 9259f0dcd95..5d41ff67757 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ConcatMapSingleTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ConcatMapSingleTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ConcatMapTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ConcatMapTckTest.java index 7629d887428..83a3774193b 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ConcatMapTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ConcatMapTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ConcatPublisherEagerTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ConcatPublisherEagerTckTest.java index 126fe4f01ad..194d7e79de9 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ConcatPublisherEagerTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ConcatPublisherEagerTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ConcatPublisherTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ConcatPublisherTckTest.java index 4bbfe152f72..ad61abd029d 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ConcatPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ConcatPublisherTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ConcatTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ConcatTckTest.java index 1ad7d79412b..c5eb360c731 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ConcatTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ConcatTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ConcatWithCompletableTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ConcatWithCompletableTckTest.java index a1431efbf8a..a5734952f5e 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ConcatWithCompletableTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ConcatWithCompletableTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ConcatWithMaybeEmptyTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ConcatWithMaybeEmptyTckTest.java index 81611f79e42..e333457b820 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ConcatWithMaybeEmptyTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ConcatWithMaybeEmptyTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ConcatWithMaybeTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ConcatWithMaybeTckTest.java index 08ecaee5ac1..b56ac86eac1 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ConcatWithMaybeTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ConcatWithMaybeTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ConcatWithSingleTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ConcatWithSingleTckTest.java index 234ebdf4199..56746e24fc4 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ConcatWithSingleTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ConcatWithSingleTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/CreateTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/CreateTckTest.java index 45a2d86ad79..ff4b0597d84 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/CreateTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/CreateTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/DefaultIfEmptyTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/DefaultIfEmptyTckTest.java index d8692cfc361..c9d9078bf5c 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/DefaultIfEmptyTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/DefaultIfEmptyTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/DeferTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/DeferTckTest.java index cb75dbb2900..f834c1e637b 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/DeferTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/DeferTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/DelaySubscriptionTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/DelaySubscriptionTckTest.java index 28cc3243d7b..5db6d0b877d 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/DelaySubscriptionTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/DelaySubscriptionTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/DelayTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/DelayTckTest.java index d2d4c08de9e..87ccaa37d2c 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/DelayTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/DelayTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/DistinctTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/DistinctTckTest.java index 35fe9537200..629d96fee60 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/DistinctTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/DistinctTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/DistinctUntilChangedTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/DistinctUntilChangedTckTest.java index 4c08351e462..ba69771a4fd 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/DistinctUntilChangedTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/DistinctUntilChangedTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/DoAfterNextTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/DoAfterNextTckTest.java index 1f988ee9f09..3b8fbebecb3 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/DoAfterNextTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/DoAfterNextTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/DoFinallyTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/DoFinallyTckTest.java index e59dc8ba7dc..029892f4403 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/DoFinallyTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/DoFinallyTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/DoOnNextTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/DoOnNextTckTest.java index 418535f8e4e..f7e343803b4 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/DoOnNextTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/DoOnNextTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ElementAtTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ElementAtTckTest.java index 1563beb090e..58e18778d02 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ElementAtTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ElementAtTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/EmptyTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/EmptyTckTest.java index 0b960f51b06..da65d54fe4e 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/EmptyTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/EmptyTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/FilterTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/FilterTckTest.java index fc3cf46588e..6c975dabfc6 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/FilterTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/FilterTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/FirstTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/FirstTckTest.java index 5dac1a42f1e..29082117ddc 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/FirstTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/FirstTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/FlatMapTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/FlatMapTckTest.java index 39b9afc4540..88e937f282e 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/FlatMapTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/FlatMapTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/FromArrayTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/FromArrayTckTest.java index d8d88a1e68d..84bcb0b70d9 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/FromArrayTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/FromArrayTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/FromCallableTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/FromCallableTckTest.java index e235109619f..d7860609333 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/FromCallableTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/FromCallableTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/FromFutureTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/FromFutureTckTest.java index 7b47ac31925..edff3c277b6 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/FromFutureTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/FromFutureTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/FromIterableTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/FromIterableTckTest.java index 0418584039f..94dc77c5557 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/FromIterableTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/FromIterableTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/FromSupplierTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/FromSupplierTckTest.java index a19028deb82..acbe1df8b02 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/FromSupplierTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/FromSupplierTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/GenerateTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/GenerateTckTest.java index 97cbb4a8113..b5c5ef30f6d 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/GenerateTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/GenerateTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/GroupByTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/GroupByTckTest.java index 7d5f0503da2..ebaedb86ae9 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/GroupByTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/GroupByTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/HideTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/HideTckTest.java index 6fa26977c17..62c3e76c4e7 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/HideTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/HideTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/IgnoreElementsTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/IgnoreElementsTckTest.java index 6a1848e88ad..289e2e90eb6 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/IgnoreElementsTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/IgnoreElementsTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/IntervalRangeTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/IntervalRangeTckTest.java index 181823e981c..b6c09d3d21a 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/IntervalRangeTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/IntervalRangeTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/IntervalTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/IntervalTckTest.java index 05a25f6774e..b9a01afc32a 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/IntervalTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/IntervalTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/IsEmptyTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/IsEmptyTckTest.java index 73cfb285502..a9ffce0294a 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/IsEmptyTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/IsEmptyTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/JustTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/JustTckTest.java index 02805e5125d..668b32a31a5 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/JustTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/JustTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/LastTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/LastTckTest.java index facdb09c32d..eb75e0342ab 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/LastTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/LastTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/LimitTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/LimitTckTest.java index 3fe61b627ac..08c526af034 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/LimitTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/LimitTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/MapTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/MapTckTest.java index 6c27b381d2b..9875c412aca 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/MapTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/MapTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/MaybeFlatMapPublisherTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/MaybeFlatMapPublisherTckTest.java index 7b582b97c5a..d23521b8abf 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/MaybeFlatMapPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/MaybeFlatMapPublisherTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/MergeIterableTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/MergeIterableTckTest.java index 79d781d8488..38a105e2be9 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/MergeIterableTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/MergeIterableTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/MergePublisherTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/MergePublisherTckTest.java index 71241d03b15..42baefbf64a 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/MergePublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/MergePublisherTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/MergeTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/MergeTckTest.java index aaefe13fee4..d0280ca83d5 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/MergeTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/MergeTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/MergeWithCompletableTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/MergeWithCompletableTckTest.java index 7345c157da2..e7cd1a2aac2 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/MergeWithCompletableTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/MergeWithCompletableTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/MergeWithMaybeEmptyTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/MergeWithMaybeEmptyTckTest.java index cb7e919577d..cd8bec50792 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/MergeWithMaybeEmptyTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/MergeWithMaybeEmptyTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/MergeWithMaybeTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/MergeWithMaybeTckTest.java index d064babcdfe..1da618c6097 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/MergeWithMaybeTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/MergeWithMaybeTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/MergeWithSingleTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/MergeWithSingleTckTest.java index cf0c894eae5..09332534185 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/MergeWithSingleTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/MergeWithSingleTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/MulticastProcessorAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/MulticastProcessorAsPublisherTckTest.java index 0c780502124..b4479181d34 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/MulticastProcessorAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/MulticastProcessorAsPublisherTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/MulticastProcessorRefCountedTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/MulticastProcessorRefCountedTckTest.java index 53b150ef5e8..907d3e3f3fc 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/MulticastProcessorRefCountedTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/MulticastProcessorRefCountedTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/MulticastProcessorTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/MulticastProcessorTckTest.java index ed6de68012b..ac82f963f7f 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/MulticastProcessorTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/MulticastProcessorTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ObserveOnTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ObserveOnTckTest.java index 4b897c82bef..d6e555be9c9 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ObserveOnTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ObserveOnTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/OnBackpressureBufferTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/OnBackpressureBufferTckTest.java index 86839c926f1..58053819aaa 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/OnBackpressureBufferTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/OnBackpressureBufferTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/OnErrorResumeWithTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/OnErrorResumeWithTckTest.java index d70e27bcf25..4d239c9f4d6 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/OnErrorResumeWithTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/OnErrorResumeWithTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/OnErrorReturnItemTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/OnErrorReturnItemTckTest.java index 708fe268296..abd7b28a4fc 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/OnErrorReturnItemTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/OnErrorReturnItemTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/PublishProcessorAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/PublishProcessorAsPublisherTckTest.java index 6154fd4b114..8e596b19958 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/PublishProcessorAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/PublishProcessorAsPublisherTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/PublishSelectorTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/PublishSelectorTckTest.java index 85cc6538257..f996fabe36f 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/PublishSelectorTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/PublishSelectorTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/PublishTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/PublishTckTest.java index 8d436c2a066..b85684d1da1 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/PublishTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/PublishTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/RangeTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/RangeTckTest.java index 3cba4e05660..53f3ca180ee 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/RangeTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/RangeTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/RebatchRequestsTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/RebatchRequestsTckTest.java index cca0025f766..c08682d2373 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/RebatchRequestsTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/RebatchRequestsTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ReduceTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ReduceTckTest.java index 70253dcafbd..94950214884 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ReduceTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ReduceTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ReduceWithTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ReduceWithTckTest.java index ba56f602c7d..9a4f4049821 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ReduceWithTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ReduceWithTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/RefCountProcessor.java b/src/test/java/io/reactivex/rxjava3/tck/RefCountProcessor.java index c65a0bd58f8..f7c62cf7525 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/RefCountProcessor.java +++ b/src/test/java/io/reactivex/rxjava3/tck/RefCountProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/RepeatTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/RepeatTckTest.java index 1af7ffa8ff9..32f5832afd3 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/RepeatTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/RepeatTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ReplayProcessorSizeBoundAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ReplayProcessorSizeBoundAsPublisherTckTest.java index 9608b573585..a32e49c6b97 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ReplayProcessorSizeBoundAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ReplayProcessorSizeBoundAsPublisherTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ReplayProcessorTimeBoundAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ReplayProcessorTimeBoundAsPublisherTckTest.java index 41e55297962..f53df02ae6a 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ReplayProcessorTimeBoundAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ReplayProcessorTimeBoundAsPublisherTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ReplayProcessorUnboundedAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ReplayProcessorUnboundedAsPublisherTckTest.java index 3bc7682284d..6f286d68def 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ReplayProcessorUnboundedAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ReplayProcessorUnboundedAsPublisherTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ReplaySelectorTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ReplaySelectorTckTest.java index e944e579553..84b1a86d451 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ReplaySelectorTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ReplaySelectorTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ReplayTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ReplayTckTest.java index 4380e957467..f62ffb08f36 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ReplayTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ReplayTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/RetryTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/RetryTckTest.java index d2608c2dce7..ba0a0f4b1fd 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/RetryTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/RetryTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ScanTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ScanTckTest.java index 231e9a25907..8a43120c020 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ScanTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ScanTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/SequenceEqualTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/SequenceEqualTckTest.java index 6c016354031..a4af22ed7eb 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/SequenceEqualTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/SequenceEqualTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ShareTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ShareTckTest.java index 6e6b57e1b5a..35c9b08e4b9 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ShareTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ShareTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/SingleFlatMapFlowableTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/SingleFlatMapFlowableTckTest.java index 653ad462c16..62565e6470a 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/SingleFlatMapFlowableTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/SingleFlatMapFlowableTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/SingleTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/SingleTckTest.java index 10de09fba7d..96af86f6bb8 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/SingleTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/SingleTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/SkipLastTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/SkipLastTckTest.java index 9583bbe646d..953986813ff 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/SkipLastTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/SkipLastTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/SkipTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/SkipTckTest.java index fcd248374ec..4f299404851 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/SkipTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/SkipTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/SkipUntilTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/SkipUntilTckTest.java index 762ca1256bd..976c4983f14 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/SkipUntilTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/SkipUntilTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/SkipWhileTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/SkipWhileTckTest.java index b560bb4694c..e4995aedd82 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/SkipWhileTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/SkipWhileTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/SortedTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/SortedTckTest.java index c8132593e21..51ff134a9c1 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/SortedTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/SortedTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/SubscribeOnTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/SubscribeOnTckTest.java index c38720d6d05..f4303d56053 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/SubscribeOnTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/SubscribeOnTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/SwitchIfEmptyTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/SwitchIfEmptyTckTest.java index 9ba97747ff6..eb792e45f08 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/SwitchIfEmptyTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/SwitchIfEmptyTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/SwitchMapDelayErrorTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/SwitchMapDelayErrorTckTest.java index cb27667aec6..d9086e275d6 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/SwitchMapDelayErrorTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/SwitchMapDelayErrorTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/SwitchMapTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/SwitchMapTckTest.java index 1d8ec8f8007..1d41a6d11b8 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/SwitchMapTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/SwitchMapTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/SwitchOnNextTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/SwitchOnNextTckTest.java index d275ca67665..196bf4f8259 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/SwitchOnNextTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/SwitchOnNextTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/TakeLastTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/TakeLastTckTest.java index 594db93c9f6..c737554363e 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/TakeLastTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/TakeLastTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/TakeTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/TakeTckTest.java index 1b2529c914f..50fe18caf1d 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/TakeTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/TakeTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/TakeUntilTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/TakeUntilTckTest.java index 256c01cc00a..96955606156 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/TakeUntilTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/TakeUntilTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/TakeWhileTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/TakeWhileTckTest.java index aa2d32939b2..24f6bd4d0d2 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/TakeWhileTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/TakeWhileTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/TimeIntervalTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/TimeIntervalTckTest.java index d0c7cd52f47..3daebf143af 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/TimeIntervalTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/TimeIntervalTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/TimeoutTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/TimeoutTckTest.java index 52ad8d01aae..447a60e9512 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/TimeoutTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/TimeoutTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/TimerTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/TimerTckTest.java index 5e280bd5201..4a6eb000058 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/TimerTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/TimerTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/TimestampTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/TimestampTckTest.java index acdef0b9ee5..48d34c87516 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/TimestampTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/TimestampTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ToListTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ToListTckTest.java index 7d7c11bf8ce..e9d17f370f3 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ToListTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ToListTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ToMapTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ToMapTckTest.java index 8fe43611894..ae27183ca09 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ToMapTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ToMapTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ToMultimapTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ToMultimapTckTest.java index 925f147a7ee..c0d65cbd338 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ToMultimapTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ToMultimapTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ToSortedListTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ToSortedListTckTest.java index fed8ec3669f..11d1029fc2b 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ToSortedListTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ToSortedListTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/UnicastProcessorAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/UnicastProcessorAsPublisherTckTest.java index 142ffbd4a7b..a888ce35fa0 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/UnicastProcessorAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/UnicastProcessorAsPublisherTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/UnicastProcessorTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/UnicastProcessorTckTest.java index 079c3492456..44bcc5a1424 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/UnicastProcessorTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/UnicastProcessorTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/UnsubscribeOnTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/UnsubscribeOnTckTest.java index c3a386f3875..1ab8398b743 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/UnsubscribeOnTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/UnsubscribeOnTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/UsingTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/UsingTckTest.java index 9c0e41f3d96..03460fdabac 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/UsingTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/UsingTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/WindowBoundaryTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/WindowBoundaryTckTest.java index bee09d0eb55..5b01ad696c9 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/WindowBoundaryTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/WindowBoundaryTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/WindowExactSizeTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/WindowExactSizeTckTest.java index 5ee35003792..dae3bf0c45d 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/WindowExactSizeTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/WindowExactSizeTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/WithLatestFromTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/WithLatestFromTckTest.java index 3d91048c37b..ae7cddb7f91 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/WithLatestFromTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/WithLatestFromTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ZipIterableTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ZipIterableTckTest.java index 8ef456e6093..9dae4bcd9a0 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ZipIterableTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ZipIterableTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ZipTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ZipTckTest.java index 4c94e97ed78..c9427876d88 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ZipTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ZipTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ZipWithIterableTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ZipWithIterableTckTest.java index 2d9eae43eab..6a4cde43f51 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ZipWithIterableTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ZipWithIterableTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/tck/ZipWithTckTest.java b/src/test/java/io/reactivex/rxjava3/tck/ZipWithTckTest.java index f71dd6b98de..6992605ad82 100644 --- a/src/test/java/io/reactivex/rxjava3/tck/ZipWithTckTest.java +++ b/src/test/java/io/reactivex/rxjava3/tck/ZipWithTckTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/testsupport/BaseTestConsumerEx.java b/src/test/java/io/reactivex/rxjava3/testsupport/BaseTestConsumerEx.java index 8eb1d9f9061..47016f1fa52 100644 --- a/src/test/java/io/reactivex/rxjava3/testsupport/BaseTestConsumerEx.java +++ b/src/test/java/io/reactivex/rxjava3/testsupport/BaseTestConsumerEx.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -16,9 +16,10 @@ import java.util.List; import io.reactivex.rxjava3.functions.Predicate; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.internal.util.ExceptionHelper; import io.reactivex.rxjava3.observers.BaseTestConsumer; +import io.reactivex.rxjava3.operators.QueueFuseable; + import java.util.Objects; /** @@ -159,7 +160,8 @@ public final U assertErrorMessage(String message) { Throwable e = errors.get(0); String errorMessage = e.getMessage(); if (!Objects.equals(message, errorMessage)) { - throw fail("Error message differs; exptected: " + message + " but was: " + errorMessage); + throw fail("\nexpected: " + message + "\ngot: " + errorMessage + + "; Error message differs"); } } else { throw fail("Multiple errors"); diff --git a/src/test/java/io/reactivex/rxjava3/testsupport/SuppressUndeliverable.java b/src/test/java/io/reactivex/rxjava3/testsupport/SuppressUndeliverable.java new file mode 100644 index 00000000000..4e701137abf --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/testsupport/SuppressUndeliverable.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.testsupport; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface SuppressUndeliverable { +} diff --git a/src/test/java/io/reactivex/rxjava3/testsupport/SuppressUndeliverableRule.java b/src/test/java/io/reactivex/rxjava3/testsupport/SuppressUndeliverableRule.java new file mode 100644 index 00000000000..28f6d2f89ec --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/testsupport/SuppressUndeliverableRule.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.testsupport; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import io.reactivex.rxjava3.exceptions.UndeliverableException; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; + +/** + * A rule for suppressing UndeliverableException handling. + * + *

Test classes that use this rule can suppress UndeliverableException + * handling by annotating the test method with SuppressUndeliverable. + */ +public class SuppressUndeliverableRule implements TestRule { + + static final class SuppressUndeliverableRuleStatement extends Statement { + private Statement base; + + SuppressUndeliverableRuleStatement(Statement base) { + this.base = base; + } + + @Override + public void evaluate() throws Throwable { + try { + RxJavaPlugins.setErrorHandler(throwable -> { + if (!(throwable instanceof UndeliverableException)) { + throwable.printStackTrace(); + Thread currentThread = Thread.currentThread(); + currentThread.getUncaughtExceptionHandler().uncaughtException(currentThread, throwable); + } + }); + base.evaluate(); + } finally { + RxJavaPlugins.setErrorHandler(null); + } + } + } + + @Override + public Statement apply(Statement base, Description description) { + if (description != null && description.getAnnotation(SuppressUndeliverable.class) != null) { + return new SuppressUndeliverableRuleStatement(base); + } else { + return base; + } + } +} diff --git a/src/test/java/io/reactivex/rxjava3/testsupport/TestHelper.java b/src/test/java/io/reactivex/rxjava3/testsupport/TestHelper.java index f50354b6a5f..d38ad8f9985 100644 --- a/src/test/java/io/reactivex/rxjava3/testsupport/TestHelper.java +++ b/src/test/java/io/reactivex/rxjava3/testsupport/TestHelper.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -30,19 +30,24 @@ import org.mockito.stubbing.Answer; import org.reactivestreams.*; +import io.reactivex.rxjava3.annotations.*; import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.operators.completable.CompletableToFlowable; import io.reactivex.rxjava3.internal.operators.maybe.MaybeToFlowable; import io.reactivex.rxjava3.internal.operators.single.SingleToFlowable; -import io.reactivex.rxjava3.internal.subscriptions.BooleanSubscription; +import io.reactivex.rxjava3.internal.subscriptions.*; import io.reactivex.rxjava3.internal.util.ExceptionHelper; import io.reactivex.rxjava3.observers.BaseTestConsumer; +import io.reactivex.rxjava3.operators.ConditionalSubscriber; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; +import io.reactivex.rxjava3.operators.SimpleQueue; import io.reactivex.rxjava3.parallel.ParallelFlowable; import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.PublishProcessor; @@ -356,6 +361,68 @@ public void onComplete() { RxJavaPlugins.setErrorHandler(null); } } + + /** + * Assert that by consuming the Publisher with a bad request amount, it is + * reported to the plugin error handler promptly. + * @param source the source to consume + */ + public static void assertBadRequestReported(ParallelFlowable source) { + List list = trackPluginErrors(); + try { + final CountDownLatch cdl = new CountDownLatch(1); + + FlowableSubscriber bad = new FlowableSubscriber() { + + @Override + public void onSubscribe(Subscription s) { + try { + s.request(-99); + s.cancel(); + s.cancel(); + } finally { + cdl.countDown(); + } + } + + @Override + public void onNext(Object t) { + + } + + @Override + public void onError(Throwable t) { + + } + + @Override + public void onComplete() { + + } + + }; + + @SuppressWarnings("unchecked") + FlowableSubscriber[] subs = new FlowableSubscriber[source.parallelism()]; + subs[0] = bad; + for (int i = 1; i < subs.length; i++) { + subs[i] = NoOpConsumer.INSTANCE; + } + source.subscribe(subs); + + try { + assertTrue(cdl.await(5, TimeUnit.SECONDS)); + } catch (InterruptedException ex) { + throw new AssertionError(ex.getMessage()); + } + + assertTrue(list.toString(), list.get(0) instanceof IllegalArgumentException); + assertEquals("n > 0 required but it was -99", list.get(0).getMessage()); + } finally { + RxJavaPlugins.setErrorHandler(null); + } + } + /** * Synchronizes the execution of two runnables (as much as possible) * to test race conditions. @@ -616,6 +683,18 @@ public static void doubleOnSubscribe(MaybeObserver observer) { } } + public static void checkDisposed(Disposable d) { + assertFalse("Disposed upfront?!", d.isDisposed()); + + d.dispose(); + + assertTrue("Not disposed?!", d.isDisposed()); + + d.dispose(); + + assertTrue("Not disposed again?!", d.isDisposed()); + } + /** * Checks if the upstream's Subscription sent through the onSubscribe reports * isCancelled properly before and after calling dispose. @@ -1485,6 +1564,69 @@ public int parallelism() { RxJavaPlugins.reset(); } } + /** + * Check if the given transformed reactive type reports multiple onSubscribe calls to + * RxJavaPlugins. + * @param the input value type + * @param transform the transform to drive an operator + */ + public static void checkDoubleOnSubscribeParallelToFlowable(Function, ? extends Flowable> transform) { + List errors = trackPluginErrors(); + try { + final Boolean[] b = { null, null, null, null }; + final CountDownLatch cdl = new CountDownLatch(2); + + ParallelFlowable source = new ParallelFlowable() { + @Override + public void subscribe(Subscriber[] subscribers) { + for (int i = 0; i < subscribers.length; i++) { + try { + BooleanSubscription bs1 = new BooleanSubscription(); + + subscribers[i].onSubscribe(bs1); + + BooleanSubscription bs2 = new BooleanSubscription(); + + subscribers[i].onSubscribe(bs2); + + b[i * 2 + 0] = bs1.isCancelled(); + b[i * 2 + 1] = bs2.isCancelled(); + } finally { + cdl.countDown(); + } + } + } + + @Override + public int parallelism() { + return 2; + } + }; + + Flowable out = transform.apply(source); + + out.subscribe(NoOpConsumer.INSTANCE); + + try { + assertTrue("Timed out", cdl.await(5, TimeUnit.SECONDS)); + } catch (InterruptedException ex) { + throw ExceptionHelper.wrapOrThrow(ex); + } + + assertEquals("Rail 1 First disposed?", false, b[0]); + assertEquals("Rail 1 Second not disposed?", true, b[1]); + + assertEquals("Rail 2 First disposed?", false, b[2]); + assertEquals("Rail 2 Second not disposed?", true, b[3]); + + assertError(errors, 0, IllegalStateException.class, "Subscription already set!"); + assertError(errors, 1, IllegalStateException.class, "Subscription already set!"); + } catch (Throwable ex) { + throw ExceptionHelper.wrapOrThrow(ex); + } finally { + RxJavaPlugins.reset(); + } + } /** * Check if the given transformed reactive type reports multiple onSubscribe calls to @@ -2248,6 +2390,30 @@ public static void checkDisposedMaybeToSingle(Function, ? extend assertFalse(pp.hasSubscribers()); } + /** + * Check if the operator applied to a Maybe source propagates dispose properly. + * @param the source value type + * @param the output value type + * @param composer the function to apply an operator to the provided Maybe source + */ + public static void checkDisposedSingleToMaybe(Function, ? extends MaybeSource> composer) { + PublishProcessor pp = PublishProcessor.create(); + + TestSubscriber ts = new TestSubscriber<>(); + + try { + new MaybeToFlowable<>(composer.apply(pp.singleOrError())).subscribe(ts); + } catch (Throwable ex) { + throw ExceptionHelper.wrapOrThrow(ex); + } + + assertTrue(pp.hasSubscribers()); + + ts.cancel(); + + assertFalse(pp.hasSubscribers()); + } + /** * Check if the TestSubscriber has a CompositeException with the specified class * of Throwables in the given order. @@ -2274,23 +2440,16 @@ public static void assertCompositeExceptions(TestSubscriberEx ts, Class ts, Object... classes) { + public static void assertCompositeExceptions(TestSubscriberEx ts, Object... classesAndMessages) { ts .assertSubscribed() .assertError(CompositeException.class) .assertNotComplete(); - List list = compositeList(ts.errors().get(0)); - - assertEquals(classes.length, list.size()); - - for (int i = 0; i < classes.length; i += 2) { - assertError(list, i, (Class)classes[i], (String)classes[i + 1]); - } + assertCompositeExceptionListOf(ts.errors().get(0), classesAndMessages); } /** @@ -2319,22 +2478,26 @@ public static void assertCompositeExceptions(TestObserverEx to, Class to, Object... classes) { + public static void assertCompositeExceptions(TestObserverEx to, Object... classesAndMessages) { to .assertSubscribed() .assertError(CompositeException.class) .assertNotComplete(); - List list = compositeList(to.errors().get(0)); + assertCompositeExceptionListOf(to.errors().get(0), classesAndMessages); + } - assertEquals(classes.length, list.size()); + @SuppressWarnings("unchecked") + static void assertCompositeExceptionListOf(Throwable ex, Object... classesAndMessages) { + List list = compositeList(ex); - for (int i = 0; i < classes.length; i += 2) { - assertError(list, i, (Class)classes[i], (String)classes[i + 1]); + assertEquals(classesAndMessages.length, 2 * list.size()); + + for (int i = 0; i < list.size(); i++) { + assertError(list, i, (Class)classesAndMessages[2 * i], (String)classesAndMessages[2 * i + 1]); } } @@ -2856,6 +3019,12 @@ public static void checkInvalidParallelSubscribers(ParallelFlowable sourc } } + /** + * Creates a fuseable Observable that does not emit anything but rejects + * fusion requests. + * @param the element type + * @return the new Observable + */ public static Observable rejectObservableFusion() { return new Observable() { @Override @@ -2904,6 +3073,12 @@ public boolean isDisposed() { }; } + /** + * Creates a fuseable Flowable that does not emit anything but rejects + * fusion requests. + * @param the element type + * @return the new Observable + */ public static Flowable rejectFlowableFusion() { return new Flowable() { @Override @@ -3341,18 +3516,26 @@ public static File findSource(String baseClassName, String parentPackage) throws parentPackage = parentPackage.replace(".", "/"); // System.out.println(path); - int i = path.toLowerCase().indexOf("/rxjava"); - if (i < 0) { - System.out.println("Can't find the base RxJava directory"); - return null; - } - - // find end of any potential postfix to /RxJava - int j = path.indexOf("/", i + 6); + // Locate the src/main/java directory + String p = null; + while (true) { + int idx = path.lastIndexOf("/"); + if (idx < 0) { + break; + } + path = path.substring(0, idx); + String check = path + "/src/main/java"; - String basePackage = path.substring(0, j + 1) + "src/main/java"; + if (new File(check).exists()) { + p = check + "/" + parentPackage + "/" + baseClassName + ".java"; + break; + } + } - String p = basePackage + "/" + parentPackage + "/" + baseClassName + ".java"; + if (p == null) { + System.err.println("Unable to locate the RxJava sources"); + return null; + } File f = new File(p); @@ -3557,4 +3740,124 @@ public static void assertError(CompletableFuture cf, Class { + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + + run.run(); + + resume.countDown(); + }); + + if (sync.decrementAndGet() != 0) { + while (sync.get() != 0) { } + } + } + + /** + * Inserts a ConditionalSubscriber into the chain to trigger the conditional paths + * without interfering with the requestFusion parts. + * @param the element type + * @return the new FlowableTransformer instance + */ + public static FlowableTransformer conditional() { + return f -> new Flowable() { + @Override + protected void subscribeActual(@NonNull Subscriber<@NonNull ? super T> subscriber) { + f.subscribe(new ForwardingConditionalSubscriber<>(subscriber)); + } + }; + } + + /** + * Wraps a Subscriber and exposes it as a fuseable conditional subscriber without interfering with + * requestFusion. + * @param the element type + */ + static final class ForwardingConditionalSubscriber extends BasicQueueSubscription implements ConditionalSubscriber { + + private static final long serialVersionUID = 365317603608134078L; + + final Subscriber downstream; + + Subscription upstream; + + QueueSubscription qs; + + ForwardingConditionalSubscriber(Subscriber downstream) { + this.downstream = downstream; + } + + @SuppressWarnings("unchecked") + @Override + public void onSubscribe(@NonNull Subscription s) { + this.upstream = s; + if (s instanceof QueueSubscription) { + this.qs = (QueueSubscription)s; + } + downstream.onSubscribe(this); + } + + @Override + public void onNext(@NonNull T t) { + downstream.onNext(t); + } + + @Override + public boolean tryOnNext(@NonNull T t) { + downstream.onNext(t); + return true; + } + + @Override + public void onError(Throwable t) { + downstream.onError(t); + } + + @Override + public void onComplete() { + downstream.onComplete(); + } + + @Override + public int requestFusion(int mode) { + return qs != null ? qs.requestFusion(mode) : 0; + } + + @Override + public @Nullable T poll() throws Throwable { + return qs.poll(); + } + + @Override + public boolean isEmpty() { + return qs.isEmpty(); + } + + @Override + public void clear() { + qs.clear(); + } + + @Override + public void request(long n) { + upstream.request(n); + } + + @Override + public void cancel() { + upstream.cancel(); + } + } } diff --git a/src/test/java/io/reactivex/rxjava3/testsupport/TestObserverEx.java b/src/test/java/io/reactivex/rxjava3/testsupport/TestObserverEx.java index ff7df2d8b3a..f029ce5457c 100644 --- a/src/test/java/io/reactivex/rxjava3/testsupport/TestObserverEx.java +++ b/src/test/java/io/reactivex/rxjava3/testsupport/TestObserverEx.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.testsupport; import java.util.concurrent.atomic.AtomicReference; @@ -17,7 +18,8 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.internal.disposables.DisposableHelper; -import io.reactivex.rxjava3.internal.fuseable.*; +import io.reactivex.rxjava3.operators.QueueDisposable; +import io.reactivex.rxjava3.operators.QueueFuseable; /** * An extended test Observer that records events and allows making assertions about them. @@ -252,8 +254,8 @@ public final TestObserverEx assertFusionMode(int mode) { int m = establishedFusionMode; if (m != mode) { if (qd != null) { - throw new AssertionError("Fusion mode different. Expected: " + fusionModeToString(mode) - + ", actual: " + fusionModeToString(m)); + throw new AssertionError("\nexpected: " + fusionModeToString(mode) + + "\ngot: " + fusionModeToString(m) + "; Fusion mode different"); } else { throw fail("Upstream is not fuseable"); } diff --git a/src/test/java/io/reactivex/rxjava3/testsupport/TestObserverExTest.java b/src/test/java/io/reactivex/rxjava3/testsupport/TestObserverExTest.java index 0d6edd6c3dd..2296ceb7576 100644 --- a/src/test/java/io/reactivex/rxjava3/testsupport/TestObserverExTest.java +++ b/src/test/java/io/reactivex/rxjava3/testsupport/TestObserverExTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -20,28 +20,24 @@ import java.util.*; import java.util.concurrent.TimeUnit; -import org.junit.*; -import org.junit.rules.ExpectedException; +import org.junit.Test; import org.mockito.InOrder; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.core.RxJavaTest; -import io.reactivex.rxjava3.disposables.*; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.internal.operators.observable.ObservableScalarXMap.ScalarDisposable; import io.reactivex.rxjava3.observers.TestObserver; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subjects.*; public class TestObserverExTest extends RxJavaTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void assertTestObserverEx() { Observable oi = Observable.fromIterable(Arrays.asList(1, 2)); @@ -55,32 +51,28 @@ public void assertTestObserverEx() { @Test public void assertNotMatchCount() { - Observable oi = Observable.fromIterable(Arrays.asList(1, 2)); - TestObserverEx subscriber = new TestObserverEx<>(); - oi.subscribe(subscriber); - - thrown.expect(AssertionError.class); - // FIXME different message format -// thrown.expectMessage("Number of items does not match. Provided: 1 Actual: 2"); - - subscriber.assertValue(1); - subscriber.assertValueCount(2); - subscriber.assertTerminated(); + assertThrows(AssertionError.class, () -> { + Observable oi = Observable.fromIterable(Arrays.asList(1, 2)); + TestObserverEx subscriber = new TestObserverEx<>(); + oi.subscribe(subscriber); + + subscriber.assertValue(1); + subscriber.assertValueCount(2); + subscriber.assertTerminated(); + }); } @Test public void assertNotMatchValue() { - Observable oi = Observable.fromIterable(Arrays.asList(1, 2)); - TestObserverEx subscriber = new TestObserverEx<>(); - oi.subscribe(subscriber); - - thrown.expect(AssertionError.class); - // FIXME different message format -// thrown.expectMessage("Value at index: 1 expected to be [3] (Integer) but was: [2] (Integer)"); - - subscriber.assertValues(1, 3); - subscriber.assertValueCount(2); - subscriber.assertTerminated(); + assertThrows(AssertionError.class, () -> { + Observable oi = Observable.fromIterable(Arrays.asList(1, 2)); + TestObserverEx subscriber = new TestObserverEx<>(); + oi.subscribe(subscriber); + + subscriber.assertValues(1, 3); + subscriber.assertValueCount(2); + subscriber.assertTerminated(); + }); } @Test @@ -96,34 +88,34 @@ public void assertNeverAtNotMatchingValue() { @Test public void assertNeverAtMatchingValue() { - Observable oi = Observable.fromIterable(Arrays.asList(1, 2)); - TestObserverEx subscriber = new TestObserverEx<>(); - oi.subscribe(subscriber); - - subscriber.assertValues(1, 2); + assertThrows(AssertionError.class, () -> { + Observable oi = Observable.fromIterable(Arrays.asList(1, 2)); + TestObserverEx subscriber = new TestObserverEx<>(); + oi.subscribe(subscriber); - thrown.expect(AssertionError.class); + subscriber.assertValues(1, 2); - subscriber.assertNever(2); - subscriber.assertValueCount(2); - subscriber.assertTerminated(); + subscriber.assertNever(2); + subscriber.assertValueCount(2); + subscriber.assertTerminated(); + }); } @Test public void assertNeverAtMatchingPredicate() { - TestObserverEx to = new TestObserverEx<>(); + assertThrows(AssertionError.class, () -> { + TestObserverEx to = new TestObserverEx<>(); - Observable.just(1, 2).subscribe(to); + Observable.just(1, 2).subscribe(to); - to.assertValues(1, 2); + to.assertValues(1, 2); - thrown.expect(AssertionError.class); - - to.assertNever(new Predicate() { - @Override - public boolean test(final Integer o) throws Exception { - return o == 1; - } + to.assertNever(new Predicate() { + @Override + public boolean test(final Integer o) throws Exception { + return o == 1; + } + }); }); } @@ -143,20 +135,18 @@ public boolean test(final Integer o) throws Exception { @Test public void assertTerminalEventNotReceived() { - PublishSubject p = PublishSubject.create(); - TestObserverEx subscriber = new TestObserverEx<>(); - p.subscribe(subscriber); + assertThrows(AssertionError.class, () -> { + PublishSubject p = PublishSubject.create(); + TestObserverEx subscriber = new TestObserverEx<>(); + p.subscribe(subscriber); - p.onNext(1); - p.onNext(2); + p.onNext(1); + p.onNext(2); - thrown.expect(AssertionError.class); - // FIXME different message format -// thrown.expectMessage("No terminal events received."); - - subscriber.assertValues(1, 2); - subscriber.assertValueCount(2); - subscriber.assertTerminated(); + subscriber.assertValues(1, 2); + subscriber.assertValueCount(2); + subscriber.assertTerminated(); + }); } @Test @@ -1148,16 +1138,16 @@ public void asyncFusion() { @Test public void assertValuePredicateEmpty() { - TestObserverEx to = new TestObserverEx<>(); + assertThrows("No values", AssertionError.class, () -> { + TestObserverEx to = new TestObserverEx<>(); - Observable.empty().subscribe(to); + Observable.empty().subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("No values"); - to.assertValue(new Predicate() { - @Override public boolean test(final Object o) throws Exception { - return false; - } + to.assertValue(new Predicate() { + @Override public boolean test(final Object o) throws Exception { + return false; + } + }); }); } @@ -1176,46 +1166,46 @@ public void assertValuePredicateMatch() { @Test public void assertValuePredicateNoMatch() { - TestObserverEx to = new TestObserverEx<>(); + assertThrows("Value not present", AssertionError.class, () -> { + TestObserverEx to = new TestObserverEx<>(); - Observable.just(1).subscribe(to); + Observable.just(1).subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("Value not present"); - to.assertValue(new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o != 1; - } + to.assertValue(new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o != 1; + } + }); }); } @Test public void assertValuePredicateMatchButMore() { - TestObserverEx to = new TestObserverEx<>(); + assertThrows("Value present but other values as well", AssertionError.class, () -> { + TestObserverEx to = new TestObserverEx<>(); - Observable.just(1, 2).subscribe(to); + Observable.just(1, 2).subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("Value present but other values as well"); - to.assertValue(new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o == 1; - } + to.assertValue(new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o == 1; + } + }); }); } @Test public void assertValueAtPredicateEmpty() { - TestObserverEx to = new TestObserverEx<>(); + assertThrows("No values", AssertionError.class, () -> { + TestObserverEx to = new TestObserverEx<>(); - Observable.empty().subscribe(to); + Observable.empty().subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("No values"); - to.assertValueAt(0, new Predicate() { - @Override public boolean test(final Object o) throws Exception { - return false; - } + to.assertValueAt(0, new Predicate() { + @Override public boolean test(final Object o) throws Exception { + return false; + } + }); }); } @@ -1234,43 +1224,43 @@ public void assertValueAtPredicateMatch() { @Test public void assertValueAtPredicateNoMatch() { - TestObserverEx to = new TestObserverEx<>(); + assertThrows("Value not present", AssertionError.class, () -> { + TestObserverEx to = new TestObserverEx<>(); - Observable.just(1, 2, 3).subscribe(to); + Observable.just(1, 2, 3).subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("Value not present"); - to.assertValueAt(2, new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o != 3; - } + to.assertValueAt(2, new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o != 3; + } + }); }); } @Test public void assertValueAtInvalidIndex() { - TestObserverEx to = new TestObserverEx<>(); + assertThrows("Invalid index: 2 (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserverEx to = new TestObserverEx<>(); - Observable.just(1, 2).subscribe(to); + Observable.just(1, 2).subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("Invalid index: 2 (latch = 0, values = 2, errors = 0, completions = 1)"); - to.assertValueAt(2, new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o == 1; - } + to.assertValueAt(2, new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o == 1; + } + }); }); } @Test public void assertValueAtIndexEmpty() { - TestObserverEx to = new TestObserverEx<>(); + assertThrows("No values", AssertionError.class, () -> { + TestObserverEx to = new TestObserverEx<>(); - Observable.empty().subscribe(to); + Observable.empty().subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("No values"); - to.assertValueAt(0, "a"); + to.assertValueAt(0, "a"); + }); } @Test @@ -1284,24 +1274,24 @@ public void assertValueAtIndexMatch() { @Test public void assertValueAtIndexNoMatch() { - TestObserverEx to = new TestObserverEx<>(); + assertThrows("\nexpected: b (class: String)\ngot: c (class: String) (latch = 0, values = 3, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserverEx to = new TestObserverEx<>(); - Observable.just("a", "b", "c").subscribe(to); + Observable.just("a", "b", "c").subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("expected: b (class: String) but was: c (class: String) (latch = 0, values = 3, errors = 0, completions = 1)"); - to.assertValueAt(2, "b"); + to.assertValueAt(2, "b"); + }); } @Test public void assertValueAtIndexInvalidIndex() { - TestObserverEx to = new TestObserverEx<>(); + assertThrows("Invalid index: 2 (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + TestObserverEx to = new TestObserverEx<>(); - Observable.just("a", "b").subscribe(to); + Observable.just("a", "b").subscribe(to); - thrown.expect(AssertionError.class); - thrown.expectMessage("Invalid index: 2 (latch = 0, values = 2, errors = 0, completions = 1)"); - to.assertValueAt(2, "c"); + to.assertValueAt(2, "c"); + }); } @Test diff --git a/src/test/java/io/reactivex/rxjava3/testsupport/TestSubscriberEx.java b/src/test/java/io/reactivex/rxjava3/testsupport/TestSubscriberEx.java index 43d4087c3e8..c3d9837c2b2 100644 --- a/src/test/java/io/reactivex/rxjava3/testsupport/TestSubscriberEx.java +++ b/src/test/java/io/reactivex/rxjava3/testsupport/TestSubscriberEx.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -10,6 +10,7 @@ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ + package io.reactivex.rxjava3.testsupport; import java.util.concurrent.atomic.*; @@ -17,8 +18,9 @@ import org.reactivestreams.*; import io.reactivex.rxjava3.core.FlowableSubscriber; -import io.reactivex.rxjava3.internal.fuseable.*; import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper; +import io.reactivex.rxjava3.operators.QueueFuseable; +import io.reactivex.rxjava3.operators.QueueSubscription; /** * An extended test subscriber that records events and allows making assertions about them. @@ -315,8 +317,8 @@ public final TestSubscriberEx assertFusionMode(int mode) { int m = establishedFusionMode; if (m != mode) { if (qs != null) { - throw new AssertionError("Fusion mode different. Expected: " + fusionModeToString(mode) - + ", actual: " + fusionModeToString(m)); + throw new AssertionError("\nexpected: " + fusionModeToString(mode) + + "\ngot: " + fusionModeToString(m) + "; Fusion mode different"); } else { throw fail("Upstream is not fuseable"); } diff --git a/src/test/java/io/reactivex/rxjava3/testsupport/TestSubscriberExTest.java b/src/test/java/io/reactivex/rxjava3/testsupport/TestSubscriberExTest.java index 308c10e0413..f3d19f9cc79 100644 --- a/src/test/java/io/reactivex/rxjava3/testsupport/TestSubscriberExTest.java +++ b/src/test/java/io/reactivex/rxjava3/testsupport/TestSubscriberExTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,8 +21,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import org.junit.*; -import org.junit.rules.ExpectedException; +import org.junit.Test; import org.mockito.InOrder; import org.reactivestreams.*; @@ -31,16 +30,13 @@ import io.reactivex.rxjava3.exceptions.*; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; -import io.reactivex.rxjava3.internal.fuseable.QueueFuseable; import io.reactivex.rxjava3.internal.subscriptions.*; +import io.reactivex.rxjava3.operators.QueueFuseable; import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.Schedulers; public class TestSubscriberExTest extends RxJavaTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void assertTestSubscriberEx() { Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); @@ -54,28 +50,28 @@ public void assertTestSubscriberEx() { @Test public void assertNotMatchCount() { - Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); - TestSubscriberEx ts = new TestSubscriberEx<>(); - oi.subscribe(ts); - - thrown.expect(AssertionError.class); + assertThrows(AssertionError.class, () -> { + Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); + TestSubscriberEx ts = new TestSubscriberEx<>(); + oi.subscribe(ts); - ts.assertValues(1); - ts.assertValueCount(2); - ts.assertTerminated(); + ts.assertValues(1); + ts.assertValueCount(2); + ts.assertTerminated(); + }); } @Test public void assertNotMatchValue() { - Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); - TestSubscriberEx ts = new TestSubscriberEx<>(); - oi.subscribe(ts); - - thrown.expect(AssertionError.class); + assertThrows(AssertionError.class, () -> { + Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); + TestSubscriberEx ts = new TestSubscriberEx<>(); + oi.subscribe(ts); - ts.assertValues(1, 3); - ts.assertValueCount(2); - ts.assertTerminated(); + ts.assertValues(1, 3); + ts.assertValueCount(2); + ts.assertTerminated(); + }); } @Test @@ -91,34 +87,34 @@ public void assertNeverAtNotMatchingValue() { @Test public void assertNeverAtMatchingValue() { - Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); - TestSubscriberEx ts = new TestSubscriberEx<>(); - oi.subscribe(ts); + assertThrows(AssertionError.class, () -> { + Flowable oi = Flowable.fromIterable(Arrays.asList(1, 2)); + TestSubscriberEx ts = new TestSubscriberEx<>(); + oi.subscribe(ts); - ts.assertValues(1, 2); - - thrown.expect(AssertionError.class); + ts.assertValues(1, 2); - ts.assertNever(2); - ts.assertValueCount(2); - ts.assertTerminated(); + ts.assertNever(2); + ts.assertValueCount(2); + ts.assertTerminated(); + }); } @Test public void assertNeverAtMatchingPredicate() { - TestSubscriberEx ts = new TestSubscriberEx<>(); + assertThrows(AssertionError.class, () -> { + TestSubscriberEx ts = new TestSubscriberEx<>(); - Flowable.just(1, 2).subscribe(ts); - - ts.assertValues(1, 2); + Flowable.just(1, 2).subscribe(ts); - thrown.expect(AssertionError.class); + ts.assertValues(1, 2); - ts.assertNever(new Predicate() { - @Override - public boolean test(final Integer o) throws Exception { - return o == 1; - } + ts.assertNever(new Predicate() { + @Override + public boolean test(final Integer o) throws Exception { + return o == 1; + } + }); }); } @@ -138,18 +134,18 @@ public boolean test(final Integer o) throws Exception { @Test public void assertTerminalEventNotReceived() { - PublishProcessor p = PublishProcessor.create(); - TestSubscriberEx ts = new TestSubscriberEx<>(); - p.subscribe(ts); - - p.onNext(1); - p.onNext(2); + assertThrows(AssertionError.class, () -> { + PublishProcessor p = PublishProcessor.create(); + TestSubscriberEx ts = new TestSubscriberEx<>(); + p.subscribe(ts); - thrown.expect(AssertionError.class); + p.onNext(1); + p.onNext(2); - ts.assertValues(1, 2); - ts.assertValueCount(2); - ts.assertTerminated(); + ts.assertValues(1, 2); + ts.assertValueCount(2); + ts.assertTerminated(); + }); } @Test @@ -1587,16 +1583,16 @@ public void asyncQueueThrows() { @Test public void assertValuePredicateEmpty() { - TestSubscriberEx ts = new TestSubscriberEx<>(); + assertThrows("No values", AssertionError.class, () -> { + TestSubscriberEx ts = new TestSubscriberEx<>(); - Flowable.empty().subscribe(ts); + Flowable.empty().subscribe(ts); - thrown.expect(AssertionError.class); - thrown.expectMessage("No values"); - ts.assertValue(new Predicate() { - @Override public boolean test(final Object o) throws Exception { - return false; - } + ts.assertValue(new Predicate() { + @Override public boolean test(final Object o) throws Exception { + return false; + } + }); }); } @@ -1615,46 +1611,46 @@ public void assertValuePredicateMatch() { @Test public void assertValuePredicateNoMatch() { - TestSubscriberEx ts = new TestSubscriberEx<>(); + assertThrows("Value not present", AssertionError.class, () -> { + TestSubscriberEx ts = new TestSubscriberEx<>(); - Flowable.just(1).subscribe(ts); + Flowable.just(1).subscribe(ts); - thrown.expect(AssertionError.class); - thrown.expectMessage("Value not present"); - ts.assertValue(new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o != 1; - } + ts.assertValue(new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o != 1; + } + }); }); } @Test public void assertValuePredicateMatchButMore() { - TestSubscriberEx ts = new TestSubscriberEx<>(); + assertThrows("Value present but other values as well", AssertionError.class, () -> { + TestSubscriberEx ts = new TestSubscriberEx<>(); - Flowable.just(1, 2).subscribe(ts); + Flowable.just(1, 2).subscribe(ts); - thrown.expect(AssertionError.class); - thrown.expectMessage("Value present but other values as well"); - ts.assertValue(new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o == 1; - } + ts.assertValue(new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o == 1; + } + }); }); } @Test public void assertValueAtPredicateEmpty() { - TestSubscriberEx ts = new TestSubscriberEx<>(); + assertThrows("No values", AssertionError.class, () -> { + TestSubscriberEx ts = new TestSubscriberEx<>(); - Flowable.empty().subscribe(ts); + Flowable.empty().subscribe(ts); - thrown.expect(AssertionError.class); - thrown.expectMessage("No values"); - ts.assertValueAt(0, new Predicate() { - @Override public boolean test(final Object o) throws Exception { - return false; - } + ts.assertValueAt(0, new Predicate() { + @Override public boolean test(final Object o) throws Exception { + return false; + } + }); }); } @@ -1673,31 +1669,31 @@ public void assertValueAtPredicateMatch() { @Test public void assertValueAtPredicateNoMatch() { - TestSubscriberEx ts = new TestSubscriberEx<>(); + assertThrows("Value not present", AssertionError.class, () -> { + TestSubscriberEx ts = new TestSubscriberEx<>(); - Flowable.just(1, 2, 3).subscribe(ts); + Flowable.just(1, 2, 3).subscribe(ts); - thrown.expect(AssertionError.class); - thrown.expectMessage("Value not present"); - ts.assertValueAt(2, new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o != 3; - } + ts.assertValueAt(2, new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o != 3; + } + }); }); } @Test public void assertValueAtInvalidIndex() { - TestSubscriberEx ts = new TestSubscriberEx<>(); + assertThrows("Invalid index: 2 (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + TestSubscriberEx ts = new TestSubscriberEx<>(); - Flowable.just(1, 2).subscribe(ts); + Flowable.just(1, 2).subscribe(ts); - thrown.expect(AssertionError.class); - thrown.expectMessage("Invalid index: 2 (latch = 0, values = 2, errors = 0, completions = 1)"); - ts.assertValueAt(2, new Predicate() { - @Override public boolean test(final Integer o) throws Exception { - return o == 1; - } + ts.assertValueAt(2, new Predicate() { + @Override public boolean test(final Integer o) throws Exception { + return o == 1; + } + }); }); } diff --git a/src/test/java/io/reactivex/rxjava3/testsupport/TimesteppingScheduler.java b/src/test/java/io/reactivex/rxjava3/testsupport/TimesteppingScheduler.java index 2615a3fbe5d..06804fa2823 100644 --- a/src/test/java/io/reactivex/rxjava3/testsupport/TimesteppingScheduler.java +++ b/src/test/java/io/reactivex/rxjava3/testsupport/TimesteppingScheduler.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/validators/BaseTypeAnnotations.java b/src/test/java/io/reactivex/rxjava3/validators/BaseTypeAnnotations.java index 504232be2eb..582df0fa712 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/BaseTypeAnnotations.java +++ b/src/test/java/io/reactivex/rxjava3/validators/BaseTypeAnnotations.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -22,6 +22,7 @@ import io.reactivex.rxjava3.annotations.*; import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.disposables.DisposableContainer; import io.reactivex.rxjava3.flowables.ConnectableFlowable; import io.reactivex.rxjava3.observables.ConnectableObservable; import io.reactivex.rxjava3.parallel.ParallelFlowable; @@ -44,7 +45,8 @@ static void checkCheckReturnValueSupport(Class clazz) { for (Method m : clazz.getMethods()) { if (m.getDeclaringClass() == clazz) { - boolean isSubscribeMethod = "subscribe".equals(m.getName()) && m.getParameterTypes().length == 0; + boolean isSubscribeMethod = "subscribe".equals(m.getName()) && + (m.getParameterTypes().length == 0 || m.getParameterTypes()[m.getParameterCount() - 1] == DisposableContainer.class); boolean isConnectMethod = "connect".equals(m.getName()) && m.getParameterTypes().length == 0; boolean isAnnotationPresent = m.isAnnotationPresent(CheckReturnValue.class); diff --git a/src/test/java/io/reactivex/rxjava3/validators/BaseTypeParser.java b/src/test/java/io/reactivex/rxjava3/validators/BaseTypeParser.java index 39704aba146..528ee6de97e 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/BaseTypeParser.java +++ b/src/test/java/io/reactivex/rxjava3/validators/BaseTypeParser.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/validators/CatchThrowIfFatalCheck.java b/src/test/java/io/reactivex/rxjava3/validators/CatchThrowIfFatalCheck.java index 5b78a2da0a5..45594fe17ba 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/CatchThrowIfFatalCheck.java +++ b/src/test/java/io/reactivex/rxjava3/validators/CatchThrowIfFatalCheck.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/validators/CheckLocalVariablesInTests.java b/src/test/java/io/reactivex/rxjava3/validators/CheckLocalVariablesInTests.java index df6f0a378a7..0ec5952f8b4 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/CheckLocalVariablesInTests.java +++ b/src/test/java/io/reactivex/rxjava3/validators/CheckLocalVariablesInTests.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/validators/FixLicenseHeaders.java b/src/test/java/io/reactivex/rxjava3/validators/FixLicenseHeaders.java index c5e601d017f..5d7223cbd1a 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/FixLicenseHeaders.java +++ b/src/test/java/io/reactivex/rxjava3/validators/FixLicenseHeaders.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -26,7 +26,7 @@ public class FixLicenseHeaders { String[] header = { - "/**", + "/*", " * Copyright (c) 2016-present, RxJava Contributors.", " *", " * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in", @@ -88,7 +88,7 @@ public void checkAndUpdateLicenses() throws Exception { in.close(); } - if (!lines.get(0).equals(header[0]) && !lines.get(1).equals(header[1])) { + if (!lines.get(0).equals(header[0]) || !lines.get(1).equals(header[1])) { fail.append("java.lang.RuntimeException: missing header added, refresh and re-run tests!\r\n") .append(" at ") ; diff --git a/src/test/java/io/reactivex/rxjava3/validators/InternalWrongNaming.java b/src/test/java/io/reactivex/rxjava3/validators/InternalWrongNaming.java index 14d937502fc..bbf86c4188e 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/InternalWrongNaming.java +++ b/src/test/java/io/reactivex/rxjava3/validators/InternalWrongNaming.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -62,7 +62,7 @@ static void checkInternalOperatorNaming(String baseClassName, String consumerCla fail.append("java.lang.RuntimeException: " + g.getName() + " mentions " + consumerClassName) .append("\r\n at io.reactivex.internal.operators.") .append(baseClassName.toLowerCase()).append(".").append(g.getName().replace(".java", "")) - .append(" (").append(g.getName()).append(":").append(i + 1).append(")\r\n\r\n"); + .append(".method(").append(g.getName()).append(":").append(i + 1).append(")\r\n\r\n"); count++; } @@ -170,6 +170,9 @@ public void flowableNoObserver() throws Exception { "FlowableCountSingle", "FlowableElementAtMaybe", "FlowableElementAtSingle", + "FlowableElementAtMaybePublisher", + "FlowableElementAtSinglePublisher", + "FlowableFromCompletable", "FlowableSingleSingle", "FlowableSingleMaybe", "FlowableLastMaybe", diff --git a/src/test/java/io/reactivex/rxjava3/validators/JavadocCodesAndLinks.java b/src/test/java/io/reactivex/rxjava3/validators/JavadocCodesAndLinks.java index 93f8cbffc08..698fdf7e831 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/JavadocCodesAndLinks.java +++ b/src/test/java/io/reactivex/rxjava3/validators/JavadocCodesAndLinks.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -32,16 +32,56 @@ public class JavadocCodesAndLinks { @Test public void checkFlowable() throws Exception { - checkSource("Flowable"); + checkSource("Flowable", "io.reactivex.rxjava3.core"); } @Test public void checkCompletable() throws Exception { - checkSource("Completable"); + checkSource("Completable", "io.reactivex.rxjava3.core"); + } + + @Test + public void checkSingle() throws Exception { + checkSource("Single", "io.reactivex.rxjava3.core"); + } + + @Test + public void checkMaybe() throws Exception { + checkSource("Maybe", "io.reactivex.rxjava3.core"); + } + + @Test + public void checkObservable() throws Exception { + checkSource("Observable", "io.reactivex.rxjava3.core"); + } + + @Test + public void checkParallelFlowable() throws Exception { + checkSource("ParallelFlowable", "io.reactivex.rxjava3.parallel"); } - static void checkSource(String baseClassName) throws Exception { - File f = TestHelper.findSource(baseClassName); + @Test + public void checkCompositeDisposable() throws Exception { + checkSource("CompositeDisposable", "io.reactivex.rxjava3.disposables"); + } + + @Test + public void checkConnectableFlowable() throws Exception { + checkSource("ConnectableFlowable", "io.reactivex.rxjava3.flowables"); + } + + @Test + public void checkConnectableObservable() throws Exception { + checkSource("ConnectableObservable", "io.reactivex.rxjava3.observables"); + } + + @Test + public void checkSchedulers() throws Exception { + checkSource("Schedulers", "io.reactivex.rxjava3.schedulers"); + } + + static void checkSource(String baseClassName, String packageName) throws Exception { + File f = TestHelper.findSource(baseClassName, packageName); if (f == null) { return; } @@ -120,6 +160,8 @@ else if (line.startsWith("@throws") || line.startsWith("@param")) { errors.append("The subsequent mention should be code: ") .append("{@code ").append(name) .append("}\r\n at ") + .append(packageName) + .append(".") .append(baseClassName) .append(".method(") .append(baseClassName) @@ -136,6 +178,8 @@ else if (line.startsWith("@throws") || line.startsWith("@param")) { errors.append("The subsequent mention should be code: ") .append("{@code ").append(name) .append("}\r\n at ") + .append(packageName) + .append(".") .append(baseClassName) .append(".method(") .append(baseClassName) @@ -152,6 +196,8 @@ else if (line.startsWith("@throws") || line.startsWith("@param")) { errors.append("The host type mention should be code: ") .append("{@code ").append(name) .append("}\r\n at ") + .append(packageName) + .append(".") .append(baseClassName) .append(".method(") .append(baseClassName) @@ -175,6 +221,8 @@ else if (line.startsWith("@throws") || line.startsWith("@param")) { errors .append(name) .append("}\r\n at ") + .append(packageName) + .append(".") .append(baseClassName) .append(".method(") .append(baseClassName) @@ -204,6 +252,8 @@ else if (line.startsWith("@throws") || line.startsWith("@param")) { errors.append("The host type mention should be code: ") .append("{@code ").append(name) .append("}\r\n at ") + .append(packageName) + .append(".") .append(baseClassName) .append(".method(") .append(baseClassName) @@ -223,6 +273,8 @@ else if (!seenBefore) { errors .append(name) .append("}\r\n at ") + .append(packageName) + .append(".") .append(baseClassName) .append(".method(") .append(baseClassName) @@ -234,6 +286,8 @@ else if (!seenBefore) { errors.append("The subsequent mention should be code: ") .append("{@code ").append(name) .append("}\r\n at ") + .append(packageName) + .append(".") .append(baseClassName) .append(".method(") .append(baseClassName) @@ -347,7 +401,7 @@ static void blankRange(StringBuilder builder, int start, int end) { "Supplier", "Callable", "TimeUnit", - "BackpressureOverflowStrategy", + "BackpressureOverflowStrategy", "ParallelFailureHandling", "Exception", "Throwable", "NullPointerException", "IllegalStateException", "IllegalArgumentException", "MissingBackpressureException", "UndeliverableException", "OutOfMemoryError", "StackOverflowError", "NoSuchElementException", "ClassCastException", "CompositeException", @@ -369,7 +423,9 @@ static void blankRange(StringBuilder builder, int start, int end) { "List", "ArrayList", "HashMap", "HashSet", "CharSequence", - "TestSubscriber", "TestObserver" + "TestSubscriber", "TestObserver", "Class", + + "ThreadFactory", "Runnable", "Executor", "ExecutorService", "Executors", "RejectedExecutionException" ); static final Set ALWAYS_CODE = new HashSet<>(Arrays.asList( diff --git a/src/test/java/io/reactivex/rxjava3/validators/JavadocFindUnescapedAngleBrackets.java b/src/test/java/io/reactivex/rxjava3/validators/JavadocFindUnescapedAngleBrackets.java index 083da2902cc..016e1b02a2c 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/JavadocFindUnescapedAngleBrackets.java +++ b/src/test/java/io/reactivex/rxjava3/validators/JavadocFindUnescapedAngleBrackets.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -12,6 +12,7 @@ */ package io.reactivex.rxjava3.validators; + import java.io.*; import java.util.*; diff --git a/src/test/java/io/reactivex/rxjava3/validators/JavadocForAnnotations.java b/src/test/java/io/reactivex/rxjava3/validators/JavadocForAnnotations.java index 14112951268..1c683783d67 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/JavadocForAnnotations.java +++ b/src/test/java/io/reactivex/rxjava3/validators/JavadocForAnnotations.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -95,7 +95,7 @@ static final void scanFor(StringBuilder sourceCode, String annotation, String in ; int lc = lineNumber(sourceCode, idx); - e.append(" at io.reactivex.").append(baseClassName) + e.append(" at io.reactivex.rxjava3.core.").append(baseClassName) .append(" (").append(baseClassName).append(".java:") .append(lc).append(")").append("\r\n\r\n"); } @@ -125,7 +125,13 @@ static final void scanForBadMethod(StringBuilder sourceCode, String annotation, if (k >= 0 && k <= idx) { int ll = sourceCode.indexOf("You specify", k); + if (ll < 0) { + ll = sourceCode.indexOf("you specify", k); + } int lm = sourceCode.indexOf("This operator", k); + if (lm < 0) { + lm = sourceCode.indexOf("this operator", k); + } if ((ll < 0 || ll > idx) && (lm < 0 || lm > idx)) { int n = sourceCode.indexOf("{@code ", k); @@ -138,27 +144,30 @@ static final void scanForBadMethod(StringBuilder sourceCode, String annotation, if (m < idx) { String mname = sourceCode.substring(n + 7, m); - int q = sourceCode.indexOf("@SuppressWarnings({", idx); + if (!"Scheduler".equals(mname)) { - int o = sourceCode.indexOf("{", idx); + int q = sourceCode.indexOf("@SuppressWarnings({", idx); - if (q + 18 == o) { - o = sourceCode.indexOf("{", q + 20); - } + int o = sourceCode.indexOf("{", idx); + + if (q + 18 == o) { + o = sourceCode.indexOf("{", q + 20); + } - if (o >= 0) { + if (o >= 0) { - int p = sourceCode.indexOf(" " + mname + "(", idx); + int p = sourceCode.indexOf(" " + mname + "(", idx); - if (p < 0 || p > o) { - // when printed on the console, IDEs will create a clickable link to help navigate to the offending point - e.append("java.lang.RuntimeException: wrong method name in description of ").append(inDoc).append(" '").append(mname).append("'\r\n") - ; - int lc = lineNumber(sourceCode, idx); + if (p < 0 || p > o) { + // when printed on the console, IDEs will create a clickable link to help navigate to the offending point + e.append("java.lang.RuntimeException: wrong method name in description of ").append(inDoc).append(" '").append(mname).append("'\r\n") + ; + int lc = lineNumber(sourceCode, idx); - e.append(" at io.reactivex.rxjava3.core.").append(baseClassName) - .append(".method(").append(baseClassName).append(".java:") - .append(lc).append(")").append("\r\n"); + e.append(" at io.reactivex.rxjava3.core.").append(baseClassName) + .append(".method(").append(baseClassName).append(".java:") + .append(lc).append(")").append("\r\n"); + } } } } diff --git a/src/test/java/io/reactivex/rxjava3/validators/JavadocWording.java b/src/test/java/io/reactivex/rxjava3/validators/JavadocWording.java index e5746cc69b6..3ab41589a3e 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/JavadocWording.java +++ b/src/test/java/io/reactivex/rxjava3/validators/JavadocWording.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -153,12 +153,12 @@ public void maybeDocRefersToMaybeTypes() throws Exception { jdx = 0; for (;;) { int idx = m.javadoc.indexOf("Single", jdx); - if (idx >= 0) { + if (idx >= 0 && m.javadoc.indexOf("Single#", jdx) != idx) { int j = m.javadoc.indexOf("#toSingle", jdx); int k = m.javadoc.indexOf("{@code Single", jdx); if (!m.signature.contains("Single") && (j + 3 != idx && k + 7 != idx)) { e.append("java.lang.RuntimeException: Maybe doc mentions Single but not in the signature\r\n at io.reactivex.rxjava3.core.") - .append("Maybe(Maybe.java:").append(m.javadocLine + lineNumber(m.javadoc, idx) - 1).append(")\r\n\r\n"); + .append("Maybe.method(Maybe.java:").append(m.javadocLine + lineNumber(m.javadoc, idx) - 1).append(")\r\n\r\n"); } jdx = idx + 6; } else { @@ -207,8 +207,11 @@ public void maybeDocRefersToMaybeTypes() throws Exception { break; } } + + checkAtReturnAndSignatureMatch("Maybe", m, e, "Flowable", "Observable", "Maybe", "Single", "Completable", "Disposable", "Iterable", "Stream", "Future", "CompletionStage"); + aOrAn(e, m, "Maybe"); - missingClosingDD(e, m, "Maybe"); + missingClosingDD(e, m, "Maybe", "io.reactivex.rxjava3.core"); backpressureMentionedWithoutAnnotation(e, m, "Maybe"); } } @@ -250,11 +253,41 @@ public void flowableDocRefersToFlowableTypes() throws Exception { } jdx = 0; for (;;) { - int idx = m.javadoc.indexOf("Observer", jdx); + int idx = m.javadoc.indexOf(" Observer", jdx); if (idx >= 0) { if (!m.signature.contains("ObservableSource") && !m.signature.contains("Observable")) { - e.append("java.lang.RuntimeException: Flowable doc mentions Observer but not using Flowable\r\n at io.reactivex.rxjava3.core.") + e.append("java.lang.RuntimeException: Flowable doc mentions Observer but not using Observable\r\n at io.reactivex.rxjava3.core.") + .append("Flowable.method(Flowable.java:").append(m.javadocLine + lineNumber(m.javadoc, idx) - 1).append(")\r\n\r\n"); + } + + jdx = idx + 6; + } else { + break; + } + } + jdx = 0; + for (;;) { + int idx = m.javadoc.indexOf(" SingleObserver", jdx); + if (idx >= 0) { + if (!m.signature.contains("SingleSource") + && !m.signature.contains("Single")) { + e.append("java.lang.RuntimeException: Flowable doc mentions SingleObserver but not using Single\r\n at io.reactivex.rxjava3.core.") + .append("Flowable.method(Flowable.java:").append(m.javadocLine + lineNumber(m.javadoc, idx) - 1).append(")\r\n\r\n"); + } + + jdx = idx + 6; + } else { + break; + } + } + jdx = 0; + for (;;) { + int idx = m.javadoc.indexOf(" MaybeObserver", jdx); + if (idx >= 0) { + if (!m.signature.contains("MaybeSource") + && !m.signature.contains("Maybe")) { + e.append("java.lang.RuntimeException: Flowable doc mentions MaybeObserver but not using Maybe\r\n at io.reactivex.rxjava3.core.") .append("Flowable.method(Flowable.java:").append(m.javadocLine + lineNumber(m.javadoc, idx) - 1).append(")\r\n\r\n"); } @@ -276,6 +309,7 @@ public void flowableDocRefersToFlowableTypes() throws Exception { && !m.signature.contains("Maybe") && !m.signature.contains("MaybeSource") && !m.signature.contains("Disposable") + && !m.signature.contains("void subscribe") ) { CharSequence subSequence = m.javadoc.subSequence(idx - 6, idx + 11); if (idx < 6 || !subSequence.equals("{@link Disposable")) { @@ -317,10 +351,10 @@ public void flowableDocRefersToFlowableTypes() throws Exception { } } - checkAtReturnAndSignatureMatch("Flowable", m, e, "Flowable", "Observable", "Maybe", "Single", "Completable"); + checkAtReturnAndSignatureMatch("Flowable", m, e, "Flowable", "Observable", "Maybe", "Single", "Completable", "ConnectableFlowable", "ParallelFlowable", "Disposable", "Iterable", "Stream", "Future", "CompletionStage"); aOrAn(e, m, "Flowable"); - missingClosingDD(e, m, "Flowable"); + missingClosingDD(e, m, "Flowable", "io.reactivex.rxjava3.core"); backpressureMentionedWithoutAnnotation(e, m, "Flowable"); } } @@ -332,6 +366,148 @@ public void flowableDocRefersToFlowableTypes() throws Exception { } } + @Test + public void parallelFlowableDocRefersToCorrectTypes() throws Exception { + List list = BaseTypeParser.parse(TestHelper.findSource("ParallelFlowable", "io.reactivex.rxjava3.parallel"), "ParallelFlowable"); + + assertFalse(list.isEmpty()); + + StringBuilder e = new StringBuilder(); + + for (RxMethod m : list) { + int jdx; + if (m.javadoc != null) { + jdx = 0; + for (;;) { + int idx = m.javadoc.indexOf("onSuccess", jdx); + if (idx >= 0) { + if (!m.signature.contains("Maybe") + && !m.signature.contains("MaybeSource") + && !m.signature.contains("Single") + && !m.signature.contains("SingleSource")) { + e.append("java.lang.RuntimeException: Flowable doc mentions onSuccess\r\n at io.reactivex.rxjava3.core.") + .append("Flowable.method(Flowable.java:").append(m.javadocLine + lineNumber(m.javadoc, idx) - 1).append(")\r\n\r\n"); + } + + jdx = idx + 6; + } else { + break; + } + } + jdx = 0; + for (;;) { + int idx = m.javadoc.indexOf(" Observer", jdx); + if (idx >= 0) { + if (!m.signature.contains("ObservableSource") + && !m.signature.contains("Observable")) { + e.append("java.lang.RuntimeException: Flowable doc mentions Observer but not using Observable\r\n at io.reactivex.rxjava3.core.") + .append("Flowable.method(Flowable.java:").append(m.javadocLine + lineNumber(m.javadoc, idx) - 1).append(")\r\n\r\n"); + } + + jdx = idx + 6; + } else { + break; + } + } + jdx = 0; + for (;;) { + int idx = m.javadoc.indexOf(" SingleObserver", jdx); + if (idx >= 0) { + if (!m.signature.contains("SingleSource") + && !m.signature.contains("Single")) { + e.append("java.lang.RuntimeException: Flowable doc mentions SingleObserver but not using Single\r\n at io.reactivex.rxjava3.core.") + .append("Flowable.method(Flowable.java:").append(m.javadocLine + lineNumber(m.javadoc, idx) - 1).append(")\r\n\r\n"); + } + + jdx = idx + 6; + } else { + break; + } + } + jdx = 0; + for (;;) { + int idx = m.javadoc.indexOf(" MaybeObserver", jdx); + if (idx >= 0) { + if (!m.signature.contains("MaybeSource") + && !m.signature.contains("Maybe")) { + e.append("java.lang.RuntimeException: Flowable doc mentions MaybeObserver but not using Maybe\r\n at io.reactivex.rxjava3.core.") + .append("Flowable.method(Flowable.java:").append(m.javadocLine + lineNumber(m.javadoc, idx) - 1).append(")\r\n\r\n"); + } + + jdx = idx + 6; + } else { + break; + } + } + jdx = 0; + for (;;) { + int idx = m.javadoc.indexOf(" Disposable", jdx); + if (idx >= 0) { + if (!m.signature.contains("Observable") + && !m.signature.contains("ObservableSource") + && !m.signature.contains("Single") + && !m.signature.contains("SingleSource") + && !m.signature.contains("Completable") + && !m.signature.contains("CompletableSource") + && !m.signature.contains("Maybe") + && !m.signature.contains("MaybeSource") + && !m.signature.contains("Disposable") + ) { + CharSequence subSequence = m.javadoc.subSequence(idx - 6, idx + 11); + if (idx < 6 || !subSequence.equals("{@link Disposable")) { + e.append("java.lang.RuntimeException: Flowable doc mentions Disposable but not using Flowable\r\n at io.reactivex.rxjava3.core.") + .append("Flowable.method(Flowable.java:").append(m.javadocLine + lineNumber(m.javadoc, idx) - 1).append(")\r\n\r\n"); + } + } + + jdx = idx + 6; + } else { + break; + } + } + jdx = 0; + for (;;) { + int idx = m.javadoc.indexOf("Observable", jdx); + if (idx >= 0) { + if (!m.signature.contains("Observable")) { + e.append("java.lang.RuntimeException: Flowable doc mentions Observable but not in the signature\r\n at io.reactivex.rxjava3.core.") + .append("Flowable.method(Flowable.java:").append(m.javadocLine + lineNumber(m.javadoc, idx) - 1).append(")\r\n\r\n"); + } + + jdx = idx + 6; + } else { + break; + } + } + jdx = 0; + for (;;) { + int idx = m.javadoc.indexOf("ObservableSource", jdx); + if (idx >= 0) { + if (!m.signature.contains("ObservableSource")) { + e.append("java.lang.RuntimeException: Flowable doc mentions ObservableSource but not in the signature\r\n at io.reactivex.rxjava3.core.") + .append("Flowable.method(Flowable.java:").append(m.javadocLine + lineNumber(m.javadoc, idx) - 1).append(")\r\n\r\n"); + } + jdx = idx + 6; + } else { + break; + } + } + + checkAtReturnAndSignatureMatch("ParallelFlowable", m, e, "Flowable", "Observable", "Maybe", "Single", "Completable", "ConnectableFlowable", "ParallelFlowable", "Disposable", "Iterable", "Stream", "Future", "CompletionStage"); + + aOrAn(e, m, "ParallelFlowable"); + missingClosingDD(e, m, "ParallelFlowable", "io.reactivex.rxjava3.parallel"); + backpressureMentionedWithoutAnnotation(e, m, "ParallelFlowable"); + } + } + + if (e.length() != 0) { + System.out.println(e); + + fail(e.toString()); + } + } + @Test public void observableDocRefersToObservableTypes() throws Exception { List list = BaseTypeParser.parse(TestHelper.findSource("Observable"), "Observable"); @@ -420,10 +596,10 @@ public void observableDocRefersToObservableTypes() throws Exception { break; } } - checkAtReturnAndSignatureMatch("Observable", m, e, "Flowable", "Observable", "Maybe", "Single", "Completable"); + checkAtReturnAndSignatureMatch("Observable", m, e, "Flowable", "Observable", "Maybe", "Single", "Completable", "ConnectableObservable", "Disposable", "Iterable", "Stream", "Future", "CompletionStage"); aOrAn(e, m, "Observable"); - missingClosingDD(e, m, "Observable"); + missingClosingDD(e, m, "Observable", "io.reactivex.rxjava3.core"); backpressureMentionedWithoutAnnotation(e, m, "Observable"); } } @@ -596,8 +772,10 @@ public void singleDocRefersToSingleTypes() throws Exception { } } + checkAtReturnAndSignatureMatch("Single", m, e, "Flowable", "Observable", "Maybe", "Single", "Completable", "Disposable", "Iterable", "Stream", "Future", "CompletionStage"); + aOrAn(e, m, "Single"); - missingClosingDD(e, m, "Single"); + missingClosingDD(e, m, "Single", "io.reactivex.rxjava3.core"); backpressureMentionedWithoutAnnotation(e, m, "Single"); } } @@ -785,10 +963,10 @@ public void completableDocRefersToCompletableTypes() throws Exception { } } - checkAtReturnAndSignatureMatch("Completable", m, e, "Flowable", "Observable", "Maybe", "Single", "Completable"); + checkAtReturnAndSignatureMatch("Completable", m, e, "Flowable", "Observable", "Maybe", "Single", "Completable", "Disposable", "Iterable", "Stream", "Future", "CompletionStage"); aOrAn(e, m, "Completable"); - missingClosingDD(e, m, "Completable"); + missingClosingDD(e, m, "Completable", "io.reactivex.rxjava3.core"); backpressureMentionedWithoutAnnotation(e, m, "Completable"); } } @@ -953,7 +1131,7 @@ static void aOrAn(StringBuilder e, RxMethod m, String wrongPre, String word, Str } } - static void missingClosingDD(StringBuilder e, RxMethod m, String baseTypeName) { + static void missingClosingDD(StringBuilder e, RxMethod m, String baseTypeName, String packageName) { int jdx = 0; for (;;) { int idx1 = m.javadoc.indexOf("
", jdx); @@ -969,7 +1147,9 @@ static void missingClosingDD(StringBuilder e, RxMethod m, String baseTypeName) { jdx = idx2 + 5; } else { e.append("java.lang.RuntimeException: unbalanced
") - .append("\r\n at io.reactivex.rxjava3.core.") + .append("\r\n at ") + .append(packageName) + .append(".") .append(baseTypeName) .append(".method(") .append(baseTypeName) @@ -990,5 +1170,5 @@ static void backpressureMentionedWithoutAnnotation(StringBuilder e, RxMethod m, } } - static final String[] AT_RETURN_WORDS = { "@return a ", "@return the new ", "@return a new " }; + static final String[] AT_RETURN_WORDS = { "@return a ", "@return an ", "@return the new ", "@return a new " }; } diff --git a/src/test/java/io/reactivex/rxjava3/validators/MaybeNo2Dot0Since.java b/src/test/java/io/reactivex/rxjava3/validators/MaybeNo2Dot0Since.java index f8b9e63164c..b8944928940 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/MaybeNo2Dot0Since.java +++ b/src/test/java/io/reactivex/rxjava3/validators/MaybeNo2Dot0Since.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/validators/NewLinesBeforeAnnotation.java b/src/test/java/io/reactivex/rxjava3/validators/NewLinesBeforeAnnotation.java index 36a0297a43a..2c27fc6fd45 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/NewLinesBeforeAnnotation.java +++ b/src/test/java/io/reactivex/rxjava3/validators/NewLinesBeforeAnnotation.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/validators/NoAnonymousInnerClassesTest.java b/src/test/java/io/reactivex/rxjava3/validators/NoAnonymousInnerClassesTest.java index 47e5d1dfd69..61db410b5b9 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/NoAnonymousInnerClassesTest.java +++ b/src/test/java/io/reactivex/rxjava3/validators/NoAnonymousInnerClassesTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/validators/NonNullMethodTypeArgumentCheck.java b/src/test/java/io/reactivex/rxjava3/validators/NonNullMethodTypeArgumentCheck.java new file mode 100644 index 00000000000..e8c4b81715e --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/validators/NonNullMethodTypeArgumentCheck.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.validators; + +import static org.junit.Assert.assertEquals; + +import java.io.*; +import java.nio.file.Files; +import java.util.*; + +import org.junit.Test; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.parallel.ParallelFlowable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; +import io.reactivex.rxjava3.testsupport.TestHelper; + +/** + * Verify static methods and final methods declaring type arguments + * declare {@code @NonNull} for said argument. + * + */ +public class NonNullMethodTypeArgumentCheck { + + static void process(Class clazz) { + + String className = clazz.getSimpleName(); + String parentPackage = clazz.getPackage().getName(); + + StringBuilder result = new StringBuilder(); + int count = 0; + + try { + File f = TestHelper.findSource(className, parentPackage); + + try (BufferedReader in = Files.newBufferedReader(f.toPath())) { + int lineCount = 1; + String line = null; + + while ((line = in.readLine()) != null) { + line = line.trim(); + + if (!line.contains(" to(")) { + if (line.startsWith("public static <") || line.startsWith("public final <")) { + + for (String ta : parseTypeArguments(line)) { + if (!ta.startsWith("@NonNull") && !ta.startsWith("@Nullable")) { + if (!("Maybe".equals(clazz.getSimpleName()) && (line.contains("fromCallable(") || line.contains("fromSupplier(")))) { + result.append("Missing annotation on argument ").append(ta).append("\r\nat ") + .append(parentPackage).append(".").append(className).append(".method(") + .append(className).append(".java:").append(lineCount).append(")\r\n"); + count++; + } + } + } + } + } + lineCount++; + } + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + if (count != 0) { + throw new IllegalArgumentException("Found " + count + " cases\r\n" + result.toString()); + } + } + + static List parseTypeArguments(String line) { + List result = new ArrayList<>(); + int offset = line.indexOf("<"); + int c = 1; + int i = offset + 1; + int j = i; + for (; i < line.length(); i++) { + if (line.charAt(i) == '<') { + c++; + } else + if (line.charAt(i) == '>') { + c--; + if (c == 0) { + break; + } + } else + if (line.charAt(i) == ',' && c == 1) { + result.add(line.substring(j, i).trim()); + j = i + 1; + } + } + result.add(line.substring(j, i).trim()); + return result; + } + + @Test + public void parseTypeArguments() { + assertEquals(new ArrayList<>(Arrays.asList("T")), parseTypeArguments("")); + assertEquals(new ArrayList<>(Arrays.asList("T", "U")), parseTypeArguments("")); + assertEquals(new ArrayList<>(Arrays.asList("T", "Flowable")), parseTypeArguments(">")); + assertEquals(new ArrayList<>(Arrays.asList("T", "Flowable")), parseTypeArguments(">")); + } + + @Test + public void flowable() { + process(Flowable.class); + } + + @Test + public void observable() { + process(Observable.class); + } + + @Test + public void maybe() { + process(Maybe.class); + } + + @Test + public void single() { + process(Single.class); + } + + @Test + public void completable() { + process(Completable.class); + } + + @Test + public void parallel() { + process(ParallelFlowable.class); + } + + @Test + public void plugins() { + process(RxJavaPlugins.class); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/validators/OperatorsAreFinal.java b/src/test/java/io/reactivex/rxjava3/validators/OperatorsAreFinal.java index 6343a6e02bf..a59e3aefa20 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/OperatorsAreFinal.java +++ b/src/test/java/io/reactivex/rxjava3/validators/OperatorsAreFinal.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/validators/OperatorsUseInterfaces.java b/src/test/java/io/reactivex/rxjava3/validators/OperatorsUseInterfaces.java new file mode 100644 index 00000000000..76d4a836f9a --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/validators/OperatorsUseInterfaces.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.validators; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.Callable; + +import org.junit.Test; +import org.reactivestreams.Publisher; + +import io.reactivex.rxjava3.core.*; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.functions.*; +import io.reactivex.rxjava3.parallel.ParallelFlowable; + +/** + * Verify that an operator method uses base interfaces as its direct input or + * has lambdas returning base interfaces. + */ +public class OperatorsUseInterfaces { + + @Test + public void checkFlowable() { + checkClass(Flowable.class); + } + + @Test + public void checkObservable() { + checkClass(Observable.class); + } + + @Test + public void checkMaybe() { + checkClass(Maybe.class); + } + + @Test + public void checkSingle() { + checkClass(Single.class); + } + + @Test + public void checkCompletable() { + checkClass(Completable.class); + } + + @Test + public void checkParallelFlowable() { + checkClass(ParallelFlowable.class); + } + + void checkClass(Class clazz) { + StringBuilder error = new StringBuilder(); + int errors = 0; + + for (Method method : clazz.getMethods()) { + if (method.getDeclaringClass() == clazz) { + int pidx = 1; + for (Parameter param : method.getParameters()) { + Class type = param.getType(); + if (type.isArray()) { + type = type.getComponentType(); + } + if (CLASSES.contains(type)) { + errors++; + error.append("Non-interface input parameter #") + .append(pidx) + .append(": ") + .append(type) + .append("\r\n") + .append(" ") + .append(method) + .append("\r\n") + ; + } + if (CAN_RETURN.contains(type)) { + Type gtype = method.getGenericParameterTypes()[pidx - 1]; + if (gtype instanceof GenericArrayType) { + gtype = ((GenericArrayType)gtype).getGenericComponentType(); + } + ParameterizedType ptype = (ParameterizedType)gtype; + for (;;) { + Type[] parameterArgTypes = ptype.getActualTypeArguments(); + Type argType = parameterArgTypes[parameterArgTypes.length - 1]; + if (argType instanceof GenericArrayType) { + argType = ((GenericArrayType)argType).getGenericComponentType(); + } + if (argType instanceof ParameterizedType) { + ParameterizedType lastArg = (ParameterizedType)argType; + + if (CLASSES.contains(lastArg.getRawType())) { + errors++; + error.append("Non-interface lambda return #") + .append(pidx) + .append(": ") + .append(type) + .append("\r\n") + .append(" ") + .append(method) + .append("\r\n") + ; + } + + if (CAN_RETURN.contains(lastArg.getRawType())) { + ptype = lastArg; + continue; + } + } + break; + } + } + pidx++; + } + } + } + + if (errors != 0) { + error.insert(0, "Found " + errors + " issues\r\n"); + fail(error.toString()); + } + } + + public void method1(Flowable f) { + // self-test + } + + public void method2(Callable> c) { + // self-test + } + + public void method3(Supplier>> c) { + // self-test + } + + public void method4(Flowable[] array) { + // self-test + } + + public void method5(Callable[]> c) { + // self-test + } + + public void method6(Callable[]>> c) { + // self-test + } + + @Test + public void checkSelf() { + try { + checkClass(OperatorsUseInterfaces.class); + throw new RuntimeException("Should have failed"); + } catch (AssertionError expected) { + assertTrue(expected.toString(), expected.toString().contains("method1")); + assertTrue(expected.toString(), expected.toString().contains("method2")); + assertTrue(expected.toString(), expected.toString().contains("method3")); + assertTrue(expected.toString(), expected.toString().contains("method4")); + assertTrue(expected.toString(), expected.toString().contains("method5")); + assertTrue(expected.toString(), expected.toString().contains("method6")); + } + } + + static final Set> CLASSES = new HashSet<>(Arrays.asList( + Flowable.class, Observable.class, + Maybe.class, Single.class, + Completable.class + )); + + static final Set> CAN_RETURN = new HashSet<>(Arrays.asList( + Callable.class, Supplier.class, + Function.class, BiFunction.class, Function3.class, Function4.class, + Function5.class, Function6.class, Function7.class, Function8.class, + Function9.class, + Publisher.class, ObservableSource.class, MaybeSource.class, SingleSource.class + )); +} diff --git a/src/test/java/io/reactivex/rxjava3/validators/ParamValidationCheckerTest.java b/src/test/java/io/reactivex/rxjava3/validators/ParamValidationCheckerTest.java index d8c3e32636e..c2ca87d4d2d 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/ParamValidationCheckerTest.java +++ b/src/test/java/io/reactivex/rxjava3/validators/ParamValidationCheckerTest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; -import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.exceptions.TestException; import io.reactivex.rxjava3.functions.*; import io.reactivex.rxjava3.internal.functions.Functions; @@ -93,7 +93,7 @@ public void checkParallelFlowable() { addOverride(new ParamOverride(Flowable.class, 0, ParamMode.NON_NEGATIVE, "elementAtOrError", Long.TYPE)); // negative skip count is ignored - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "skip", Long.TYPE)); + addOverride(new ParamOverride(Flowable.class, 0, ParamMode.NON_NEGATIVE, "skip", Long.TYPE)); // negative skip time is considered as zero skip time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "skip", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "skip", Long.TYPE, TimeUnit.class, Scheduler.class)); @@ -125,10 +125,6 @@ public void checkParallelFlowable() { // negative timeout is allowed addOverride(new ParamOverride(Flowable.class, 1, ParamMode.ANY, "fromFuture", Future.class, Long.TYPE, TimeUnit.class)); - addOverride(new ParamOverride(Flowable.class, 1, ParamMode.ANY, "fromFuture", Future.class, Long.TYPE, TimeUnit.class, Scheduler.class)); - - // null default is allowed - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "blockingLast", Object.class)); // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "timer", Long.TYPE, TimeUnit.class)); @@ -146,22 +142,18 @@ public void checkParallelFlowable() { addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); - // null default is allowed - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "blockingMostRecent", Object.class)); - // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "delaySubscription", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "delaySubscription", Long.TYPE, TimeUnit.class, Scheduler.class)); - // null default is allowed - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "blockingFirst", Object.class)); - // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "debounce", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "debounce", Long.TYPE, TimeUnit.class, Scheduler.class)); + addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "debounce", Long.TYPE, TimeUnit.class, Scheduler.class, Consumer.class)); // null Action allowed addOverride(new ParamOverride(Flowable.class, 1, ParamMode.ANY, "onBackpressureBuffer", Long.TYPE, Action.class, BackpressureOverflowStrategy.class)); + addOverride(new ParamOverride(Flowable.class, 1, ParamMode.ANY, "onBackpressureBuffer", Long.TYPE, Action.class, BackpressureOverflowStrategy.class, Consumer.class)); // zero repeat is allowed addOverride(new ParamOverride(Flowable.class, 0, ParamMode.NON_NEGATIVE, "repeat", Long.TYPE)); @@ -187,6 +179,7 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleWithTimeout", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleWithTimeout", Long.TYPE, TimeUnit.class, Scheduler.class)); + addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleWithTimeout", Long.TYPE, TimeUnit.class, Scheduler.class, Consumer.class)); // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "take", Long.TYPE, TimeUnit.class)); @@ -200,6 +193,7 @@ public void checkParallelFlowable() { addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); + addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Consumer.class)); // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class)); @@ -230,16 +224,19 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleFirst", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleFirst", Long.TYPE, TimeUnit.class, Scheduler.class)); + addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleFirst", Long.TYPE, TimeUnit.class, Scheduler.class, Consumer.class)); // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLast", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLast", Long.TYPE, TimeUnit.class, Scheduler.class)); + addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLast", Long.TYPE, TimeUnit.class, Scheduler.class, Consumer.class)); // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); + addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Consumer.class)); // negative buffer time is considered as zero buffer time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "window", Long.TYPE, TimeUnit.class)); @@ -299,6 +296,8 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Maybe.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Maybe.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class)); + addOverride(new ParamOverride(Maybe.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Boolean.TYPE)); + addOverride(new ParamOverride(Maybe.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); // zero repeat is allowed addOverride(new ParamOverride(Maybe.class, 0, ParamMode.NON_NEGATIVE, "repeat", Long.TYPE)); @@ -325,7 +324,6 @@ public void checkParallelFlowable() { // negative timeout is allowed addOverride(new ParamOverride(Single.class, 1, ParamMode.ANY, "fromFuture", Future.class, Long.TYPE, TimeUnit.class)); - addOverride(new ParamOverride(Single.class, 1, ParamMode.ANY, "fromFuture", Future.class, Long.TYPE, TimeUnit.class, Scheduler.class)); // negative time is considered as zero time addOverride(new ParamOverride(Single.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class)); @@ -353,7 +351,7 @@ public void checkParallelFlowable() { addOverride(new ParamOverride(Observable.class, 0, ParamMode.NON_NEGATIVE, "elementAtOrError", Long.TYPE)); // negative skip count is ignored - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "skip", Long.TYPE)); + addOverride(new ParamOverride(Observable.class, 0, ParamMode.NON_NEGATIVE, "skip", Long.TYPE)); // negative skip time is considered as zero skip time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "skip", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "skip", Long.TYPE, TimeUnit.class, Scheduler.class)); @@ -381,10 +379,6 @@ public void checkParallelFlowable() { // negative timeout is allowed addOverride(new ParamOverride(Observable.class, 1, ParamMode.ANY, "fromFuture", Future.class, Long.TYPE, TimeUnit.class)); - addOverride(new ParamOverride(Observable.class, 1, ParamMode.ANY, "fromFuture", Future.class, Long.TYPE, TimeUnit.class, Scheduler.class)); - - // null default is allowed - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "blockingLast", Object.class)); // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "timer", Long.TYPE, TimeUnit.class)); @@ -402,19 +396,14 @@ public void checkParallelFlowable() { addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); - // null default is allowed - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "blockingMostRecent", Object.class)); - // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "delaySubscription", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "delaySubscription", Long.TYPE, TimeUnit.class, Scheduler.class)); - // null default is allowed - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "blockingFirst", Object.class)); - // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "debounce", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "debounce", Long.TYPE, TimeUnit.class, Scheduler.class)); + addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "debounce", Long.TYPE, TimeUnit.class, Scheduler.class, Consumer.class)); // zero repeat is allowed addOverride(new ParamOverride(Observable.class, 0, ParamMode.NON_NEGATIVE, "repeat", Long.TYPE)); @@ -440,6 +429,7 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleWithTimeout", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleWithTimeout", Long.TYPE, TimeUnit.class, Scheduler.class)); + addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleWithTimeout", Long.TYPE, TimeUnit.class, Scheduler.class, Consumer.class)); // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "take", Long.TYPE, TimeUnit.class)); @@ -453,6 +443,7 @@ public void checkParallelFlowable() { addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); + addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Consumer.class)); // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class)); @@ -483,16 +474,19 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleFirst", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleFirst", Long.TYPE, TimeUnit.class, Scheduler.class)); + addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleFirst", Long.TYPE, TimeUnit.class, Scheduler.class, Consumer.class)); // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLast", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLast", Long.TYPE, TimeUnit.class, Scheduler.class)); + addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLast", Long.TYPE, TimeUnit.class, Scheduler.class, Consumer.class)); // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); + addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Consumer.class)); // negative buffer time is considered as zero buffer time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "window", Long.TYPE, TimeUnit.class)); @@ -579,6 +573,7 @@ public void checkParallelFlowable() { for (Class interfaces : AllFunctionals.class.getInterfaces()) { defaultValues.put(interfaces, af); } + defaultValues.put(Subscriber.class, af); defaultValues.put(TimeUnit.class, TimeUnit.SECONDS); defaultValues.put(Scheduler.class, Schedulers.single()); defaultValues.put(BackpressureStrategy.class, BackpressureStrategy.MISSING); @@ -599,6 +594,8 @@ public void checkParallelFlowable() { defaultValues.put(ParallelFailureHandling.class, ParallelFailureHandling.ERROR); + defaultValues.put(DisposableContainer.class, new CompositeDisposable()); + // JDK 8 types defaultValues.put(Optional.class, Optional.of(1)); @@ -893,6 +890,12 @@ void checkClass(Class clazz) { error = ex; } + if (!success && error.getCause() instanceof NullPointerException) { + if (!error.getCause().toString().contains("is null")) { + fail++; + b.append("\r\nNPEs should indicate which argument failed: " + m + " # " + i + " = " + p + ", tag = " + tag + ", params = " + Arrays.toString(callParams2)); + } + } if (success != shouldSucceed) { fail++; if (shouldSucceed) { @@ -937,7 +940,7 @@ static final class AllFunctionals Function3, Function4, Function5, Function6, Function7, Function8, Function9, FlowableOnSubscribe, ObservableOnSubscribe, SingleOnSubscribe, MaybeOnSubscribe, CompletableOnSubscribe, FlowableTransformer, ObservableTransformer, SingleTransformer, MaybeTransformer, CompletableTransformer, - Subscriber, FlowableSubscriber, Observer, SingleObserver, MaybeObserver, CompletableObserver, + FlowableSubscriber, Observer, SingleObserver, MaybeObserver, CompletableObserver, FlowableOperator, ObservableOperator, SingleOperator, MaybeOperator, CompletableOperator, Comparator, ParallelTransformer { @@ -1222,4 +1225,4 @@ public String toString() { return "NeverCompletable"; } } -} +} \ No newline at end of file diff --git a/src/test/java/io/reactivex/rxjava3/validators/ParamValidationNaming.java b/src/test/java/io/reactivex/rxjava3/validators/ParamValidationNaming.java index 7ab384f5d36..1928fbee60b 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/ParamValidationNaming.java +++ b/src/test/java/io/reactivex/rxjava3/validators/ParamValidationNaming.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -21,7 +21,7 @@ import io.reactivex.rxjava3.core.*; import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.disposables.*; import io.reactivex.rxjava3.flowables.ConnectableFlowable; import io.reactivex.rxjava3.observables.ConnectableObservable; import io.reactivex.rxjava3.parallel.ParallelFlowable; @@ -172,6 +172,11 @@ public void checkMulticastProcessor() throws Exception { processFile(MulticastProcessor.class); } + @Test + public void checkCompositeDisposable() throws Exception { + processFile(CompositeDisposable.class); + } + static void processFile(Class clazz) throws Exception { String baseClassName = clazz.getSimpleName(); File f = TestHelper.findSource(baseClassName, clazz.getPackage().getName()); @@ -189,17 +194,22 @@ static void processFile(Class clazz) throws Exception { String line = lines.get(j).trim(); for (ValidatorStrings validatorStr : VALIDATOR_STRINGS) { - if (line.startsWith(validatorStr.code)) { + int strIdx = line.indexOf(validatorStr.code); + if (strIdx >= 0) { - int comma = line.indexOf(','); + int comma = line.indexOf(',', strIdx + validatorStr.code.length()); - String paramName = line.substring(validatorStr.code.length(), comma); + String paramName = line.substring(strIdx + validatorStr.code.length(), comma); int quote = line.indexOf('"', comma); - String message = line.substring(quote + 1, quote + 2 + paramName.length()); + String message = line.substring(quote + 1, Math.min(line.length(), quote + 2 + paramName.length())); - if (!line.contains("The RxJavaPlugins") + if (line.contains("\"A Disposable")) { + continue; + } + + if (!line.contains("\"The RxJavaPlugins") && !(message.startsWith(paramName) && (message.endsWith(" ") || message.endsWith("\"")))) { errorCount++; @@ -219,19 +229,31 @@ static void processFile(Class clazz) throws Exception { ; } - // FIXME enable for other types in separate PR! - if (!baseClassName.equals("Completable")) { + int midx = j - 1; + // find the method declaration + for (; midx >= 0; midx--) { + String linek = lines.get(midx).trim(); + if (linek.startsWith("public") || linek.startsWith("private") + || linek.startsWith("protected") + || linek.startsWith("static") + || linek.startsWith(baseClassName)) { + break; + } + } + + if (line.contains("\"The RxJavaPlugins")) { continue; } + // find JavaDoc of throws boolean found = false; - for (int k = j - 1; k >= 0; k--) { + for (int k = midx - 1; k >= 0; k--) { String linek = lines.get(k).trim(); if (linek.startsWith("/**")) { break; } if (linek.startsWith("}")) { - found = true; // no JavaDoc + found = true; // no method JavaDoc present break; } if (linek.startsWith(validatorStr.javadoc)) { @@ -274,6 +296,130 @@ static void processFile(Class clazz) throws Exception { } } } + + for (ValidatorStrings validatorStr : EXCEPTION_STRINGS) { + int strIdx = line.indexOf(validatorStr.code); + if (strIdx >= 0) { + + int midx = j - 1; + // find the method declaration + for (; midx >= 0; midx--) { + String linek = lines.get(midx).trim(); + if (linek.startsWith("public") || linek.startsWith("private") + || linek.startsWith("protected") + || linek.startsWith("static") + || linek.startsWith(baseClassName)) { + break; + } + } + + // find JavaDoc of throws + boolean found = false; + for (int k = midx - 1; k >= 0; k--) { + String linek = lines.get(k).trim(); + if (linek.startsWith("/**")) { + break; + } + if (linek.startsWith("}")) { + found = true; // no JavaDoc + break; + } + if (linek.startsWith(validatorStr.javadoc)) { + found = true; + } + } + + if (!found) { + errorCount++; + errors.append("L") + .append(j) + .append(" : missing '") + .append(validatorStr.javadoc) + .append("' for exception\r\n ") + .append(line) + .append("\r\n at ") + .append(fullClassName) + .append(".method(") + .append(f.getName()) + .append(":") + .append(j + 1) + .append(")\r\n") + ; + } + } + } + + if (line.startsWith("public") || line.startsWith("protected") || line.startsWith("final") || line.startsWith("private") + || line.startsWith("static")) { + for (ValidatorStrings validatorStr : TYPICAL_ARGUMENT_STRINGS) { + // find the method declaration ending { + for (int i = j; i < lines.size(); i++) { + String linei = lines.get(i).trim(); + + // space + code for capturing type declarations + String varPattern = " " + validatorStr.code; + if (linei.contains(varPattern + ")") + || linei.contains(varPattern + ",") + || linei.endsWith(varPattern)) { + // ignore nullable-annotated arguments + if (!linei.matches(".*\\@Nullable\\s.*" + validatorStr.code + ".*")) { + boolean found = false; + for (int k = i - 1; k >= 0; k--) { + String linek = lines.get(k).trim(); + if (linek.startsWith("/**")) { + break; + } + if (linek.startsWith("}")) { + found = true; // no method JavaDoc present + break; + } + if (linek.startsWith(validatorStr.javadoc)) { + // see if a @code paramName is present + String paramStr = "{@code " + validatorStr.code + "}"; + for (int m = k; m < lines.size(); m++) { + String linem = lines.get(m).trim(); + if (linem.startsWith("* @see") + || linem.startsWith("* @since") + || linem.startsWith("*/")) { + break; + } + if (linem.contains(paramStr)) { + found = true; + break; + } + } + break; + } + } + + if (!found) { + errorCount++; + errors.append("L") + .append(j) + .append(" : missing '") + .append(validatorStr.javadoc) + .append("' for typical argument: ") + .append(validatorStr.code) + .append("\r\n ") + .append(line) + .append("\r\n at ") + .append(fullClassName) + .append(".method(") + .append(f.getName()) + .append(":") + .append(j + 1) + .append(")\r\n") + ; + } + } + } + + if (linei.endsWith("{") || linei.endsWith(";")) { + break; + } + } + } + } } if (errorCount != 0) { @@ -297,4 +443,100 @@ static final class ValidatorStrings { new ValidatorStrings("ObjectHelper.verifyPositive(", "* @throws IllegalArgumentException") ); + static final List EXCEPTION_STRINGS = Arrays.asList( + new ValidatorStrings("throw new NullPointerException(", "* @throws NullPointerException"), + new ValidatorStrings("throw new IllegalArgumentException(", "* @throws IllegalArgumentException"), + new ValidatorStrings("throw new IndexOutOfBoundsException(", "* @throws IndexOutOfBoundsException") + ); + + static final List TYPICAL_ARGUMENT_STRINGS = Arrays.asList( + new ValidatorStrings("source", "* @throws NullPointerException"), + new ValidatorStrings("source1", "* @throws NullPointerException"), + new ValidatorStrings("source2", "* @throws NullPointerException"), + new ValidatorStrings("source3", "* @throws NullPointerException"), + new ValidatorStrings("source4", "* @throws NullPointerException"), + new ValidatorStrings("source5", "* @throws NullPointerException"), + new ValidatorStrings("source6", "* @throws NullPointerException"), + new ValidatorStrings("source7", "* @throws NullPointerException"), + new ValidatorStrings("source8", "* @throws NullPointerException"), + new ValidatorStrings("source9", "* @throws NullPointerException"), + new ValidatorStrings("sources", "* @throws NullPointerException"), + new ValidatorStrings("mapper", "* @throws NullPointerException"), + new ValidatorStrings("combiner", "* @throws NullPointerException"), + new ValidatorStrings("zipper", "* @throws NullPointerException"), + new ValidatorStrings("predicate", "* @throws NullPointerException"), + new ValidatorStrings("item", "* @throws NullPointerException"), + new ValidatorStrings("item1", "* @throws NullPointerException"), + new ValidatorStrings("item2", "* @throws NullPointerException"), + new ValidatorStrings("item3", "* @throws NullPointerException"), + new ValidatorStrings("item4", "* @throws NullPointerException"), + new ValidatorStrings("item5", "* @throws NullPointerException"), + new ValidatorStrings("item6", "* @throws NullPointerException"), + new ValidatorStrings("item7", "* @throws NullPointerException"), + new ValidatorStrings("item8", "* @throws NullPointerException"), + new ValidatorStrings("item9", "* @throws NullPointerException"), + new ValidatorStrings("item10", "* @throws NullPointerException"), + new ValidatorStrings("unit", "* @throws NullPointerException"), + new ValidatorStrings("scheduler", "* @throws NullPointerException"), + new ValidatorStrings("other", "* @throws NullPointerException"), + new ValidatorStrings("fallback", "* @throws NullPointerException"), + new ValidatorStrings("defaultItem", "* @throws NullPointerException"), + new ValidatorStrings("defaultValue", "* @throws NullPointerException"), + new ValidatorStrings("stop", "* @throws NullPointerException"), + new ValidatorStrings("stopPredicate", "* @throws NullPointerException"), + new ValidatorStrings("handler", "* @throws NullPointerException"), + new ValidatorStrings("bufferSupplier", "* @throws NullPointerException"), + new ValidatorStrings("openingIndicator", "* @throws NullPointerException"), + new ValidatorStrings("closingIndicator", "* @throws NullPointerException"), + new ValidatorStrings("boundary", "* @throws NullPointerException"), + new ValidatorStrings("boundaryIndicator", "* @throws NullPointerException"), + new ValidatorStrings("selector", "* @throws NullPointerException"), + new ValidatorStrings("resultSelector", "* @throws NullPointerException"), + new ValidatorStrings("keySelector", "* @throws NullPointerException"), + new ValidatorStrings("valueSelector", "* @throws NullPointerException"), + new ValidatorStrings("valueSupplier", "* @throws NullPointerException"), + new ValidatorStrings("collectionSupplier", "* @throws NullPointerException"), + new ValidatorStrings("onNext", "* @throws NullPointerException"), + new ValidatorStrings("onError", "* @throws NullPointerException"), + new ValidatorStrings("onComplete", "* @throws NullPointerException"), + new ValidatorStrings("onEvent", "* @throws NullPointerException"), + new ValidatorStrings("onAfterNext", "* @throws NullPointerException"), + new ValidatorStrings("onAfterTerminate", "* @throws NullPointerException"), + new ValidatorStrings("onTerminate", "* @throws NullPointerException"), + new ValidatorStrings("onSuccess", "* @throws NullPointerException"), + new ValidatorStrings("onSubscribe", "* @throws NullPointerException"), + new ValidatorStrings("onNotification", "* @throws NullPointerException"), + new ValidatorStrings("onCancel", "* @throws NullPointerException"), + new ValidatorStrings("onDispose", "* @throws NullPointerException"), + new ValidatorStrings("onRequest", "* @throws NullPointerException"), + new ValidatorStrings("onNextMapper", "* @throws NullPointerException"), + new ValidatorStrings("onErrorMapper", "* @throws NullPointerException"), + new ValidatorStrings("onCompleteSupplier", "* @throws NullPointerException"), + new ValidatorStrings("clazz", "* @throws NullPointerException"), + new ValidatorStrings("next", "* @throws NullPointerException"), + new ValidatorStrings("reducer", "* @throws NullPointerException"), + new ValidatorStrings("seed", "* @throws NullPointerException"), + new ValidatorStrings("seedSupplier", "* @throws NullPointerException"), + new ValidatorStrings("mapSupplier", "* @throws NullPointerException"), + new ValidatorStrings("collectionFactory", "* @throws NullPointerException"), + new ValidatorStrings("factory", "* @throws NullPointerException"), + new ValidatorStrings("stage", "* @throws NullPointerException"), + new ValidatorStrings("stream", "* @throws NullPointerException"), + new ValidatorStrings("collector", "* @throws NullPointerException"), + new ValidatorStrings("subscriptionIndicator", "* @throws NullPointerException"), + new ValidatorStrings("itemDelayIndicator", "* @throws NullPointerException"), + new ValidatorStrings("future", "* @throws NullPointerException"), + + new ValidatorStrings("maxConcurrency", "* @throws IllegalArgumentException"), + new ValidatorStrings("parallelism", "* @throws IllegalArgumentException"), + new ValidatorStrings("prefetch", "* @throws IllegalArgumentException"), + new ValidatorStrings("bufferSize", "* @throws IllegalArgumentException"), + new ValidatorStrings("capacityHint", "* @throws IllegalArgumentException"), + new ValidatorStrings("capacity", "* @throws IllegalArgumentException"), + new ValidatorStrings("count", "* @throws IllegalArgumentException"), + new ValidatorStrings("skip", "* @throws IllegalArgumentException"), + new ValidatorStrings("times", "* @throws IllegalArgumentException"), + new ValidatorStrings("n", "* @throws IllegalArgumentException") + ); + } diff --git a/src/test/java/io/reactivex/rxjava3/validators/ParameterNamesInClassesTest.java b/src/test/java/io/reactivex/rxjava3/validators/ParameterNamesInClassesTest.java new file mode 100644 index 00000000000..2284e32f6ab --- /dev/null +++ b/src/test/java/io/reactivex/rxjava3/validators/ParameterNamesInClassesTest.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava3.validators; + +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class ParameterNamesInClassesTest { + void method(int paramName) { + // deliberately empty + } + + @Test + public void javacParametersEnabled() throws Exception { + assertEquals("Please enable saving parameter names via the -parameters javac argument", + "paramName", + getClass() + .getDeclaredMethod("method", Integer.TYPE) + .getParameters()[0].getName()); + } +} diff --git a/src/test/java/io/reactivex/rxjava3/validators/PublicFinalMethods.java b/src/test/java/io/reactivex/rxjava3/validators/PublicFinalMethods.java index f7f59d630d0..ad7df44964e 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/PublicFinalMethods.java +++ b/src/test/java/io/reactivex/rxjava3/validators/PublicFinalMethods.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/validators/SourceAnnotationCheck.java b/src/test/java/io/reactivex/rxjava3/validators/SourceAnnotationCheck.java index 6fb50a141be..dfa4aea548b 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/SourceAnnotationCheck.java +++ b/src/test/java/io/reactivex/rxjava3/validators/SourceAnnotationCheck.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in @@ -25,6 +25,7 @@ import io.reactivex.rxjava3.flowables.ConnectableFlowable; import io.reactivex.rxjava3.observables.ConnectableObservable; import io.reactivex.rxjava3.parallel.ParallelFlowable; +import io.reactivex.rxjava3.plugins.RxJavaPlugins; import io.reactivex.rxjava3.processors.*; import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subjects.*; @@ -172,6 +173,11 @@ public void checkMulticastProcessor() throws Exception { processFile(MulticastProcessor.class); } + @Test + public void checkRxJavaPlugins() throws Exception { + processFile(RxJavaPlugins.class); + } + static void processFile(Class clazz) throws Exception { String baseClassName = clazz.getSimpleName(); File f = TestHelper.findSource(baseClassName, clazz.getPackage().getName()); @@ -376,6 +382,67 @@ else if (skippingDepth == 0) { ; } } + + for (String typeName : TYPES_REQUIRING_NONNULL_TYPEARG) { + String pattern = typeName + ".*"; + if (line.contains(pattern) && !line.matches(patternRegex)) { + + errorCount++; + errors.append("L") + .append(j) + .append(" : Missing @NonNull type argument annotation on ") + .append(typeName) + .append("\r\n") + .append(" at ") + .append(fullClassName) + .append(".method(") + .append(f.getName()) + .append(":") + .append(j + 1) + .append(")\r\n") + ; + } + } + for (String typeName : TYPES_FORBIDDEN_NONNULL_TYPEARG) { + String patternRegex = ".*" + typeName + "\\<@NonNull (\\? (extends|super) )?" + COMMON_TYPE_ARG_NAMES + "\\>.*"; + + if (line.matches(patternRegex)) { + errorCount++; + errors.append("L") + .append(j) + .append(" : @NonNull type argument should be on the arg declaration ") + .append(typeName) + .append("\r\n") + .append(" at ") + .append(fullClassName) + .append(".method(") + .append(f.getName()) + .append(":") + .append(j + 1) + .append(")\r\n") + ; + } + } + + for (String typeName : TYPES_REQUIRING_NONNULL_TYPEARG_ON_FUNC) { + if (line.matches(".*Function[\\d]?\\<.*, (\\? (extends|super) )?" + typeName + ".*")) { + errorCount++; + errors.append("L") + .append(j) + .append(" : Missing @NonNull type argument annotation on Function argument ") + .append(typeName) + .append("\r\n") + .append(" at ") + .append(fullClassName) + .append(".method(") + .append(f.getName()) + .append(":") + .append(j + 1) + .append(")\r\n") + ; + } + } } if (errorCount != 0) { @@ -417,4 +484,18 @@ else if (skippingDepth == 0) { "T", "R", "U", "V" ); + + static final List TYPES_REQUIRING_NONNULL_TYPEARG = Arrays.asList( + "Iterable", "Stream", "Publisher", "Processor", "Subscriber", "Optional" + ); + static final List TYPES_FORBIDDEN_NONNULL_TYPEARG = Arrays.asList( + "Iterable", "Stream", "Publisher", "Processor", "Subscriber", "Optional" + ); + + static final List TYPES_REQUIRING_NONNULL_TYPEARG_ON_FUNC = Arrays.asList( + "Iterable", "Stream", "Publisher", "Processor", "Subscriber", "Optional", + "Observer", "SingleObserver", "MaybeObserver", "CompletableObserver" + ); + + static final String COMMON_TYPE_ARG_NAMES = "([A-Z][0-9]?|TOpening|TClosing|TLeft|TLeftEnd|TRight|TRightEnd)"; } diff --git a/src/test/java/io/reactivex/rxjava3/validators/TestPrefixInMethodName.java b/src/test/java/io/reactivex/rxjava3/validators/TestPrefixInMethodName.java index 2fb3460a73a..7a75611b10c 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/TestPrefixInMethodName.java +++ b/src/test/java/io/reactivex/rxjava3/validators/TestPrefixInMethodName.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/validators/TextualAorAn.java b/src/test/java/io/reactivex/rxjava3/validators/TextualAorAn.java index 6aff9cc10e1..654b4884b42 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/TextualAorAn.java +++ b/src/test/java/io/reactivex/rxjava3/validators/TextualAorAn.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in diff --git a/src/test/java/io/reactivex/rxjava3/validators/TooManyEmptyNewLines.java b/src/test/java/io/reactivex/rxjava3/validators/TooManyEmptyNewLines.java index 581e78301b6..c79c879337a 100644 --- a/src/test/java/io/reactivex/rxjava3/validators/TooManyEmptyNewLines.java +++ b/src/test/java/io/reactivex/rxjava3/validators/TooManyEmptyNewLines.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in